From 60f33dfdfadb466caee55fdfa6c95e14393e85ed Mon Sep 17 00:00:00 2001 From: JinmaoLi Date: Tue, 2 Jul 2024 06:26:27 +0000 Subject: [PATCH] support aggr-first in/exists subquery pullup --- .../rewrite/ob_transform_aggr_subquery.cpp | 624 +++++++++++++++--- src/sql/rewrite/ob_transform_aggr_subquery.h | 57 +- .../ob_transform_simplify_subquery.cpp | 378 +---------- .../rewrite/ob_transform_simplify_subquery.h | 12 - src/sql/rewrite/ob_transform_utils.cpp | 507 ++++++++++++++ src/sql/rewrite/ob_transform_utils.h | 32 + 6 files changed, 1113 insertions(+), 497 deletions(-) diff --git a/src/sql/rewrite/ob_transform_aggr_subquery.cpp b/src/sql/rewrite/ob_transform_aggr_subquery.cpp index 7faaa93c4d..526badbfce 100644 --- a/src/sql/rewrite/ob_transform_aggr_subquery.cpp +++ b/src/sql/rewrite/ob_transform_aggr_subquery.cpp @@ -296,8 +296,10 @@ int ObTransformAggrSubquery::do_aggr_first_transform(ObDMLStmt *&stmt, TransformParam &trans_param = transform_params.at(i); ObQueryRefRawExpr *query_ref = NULL; ObSelectStmt *subquery = NULL; + ObSelectStmt *origin_subquery = NULL; if (OB_ISNULL(query_ref = trans_param.ja_query_ref_) || - OB_ISNULL(subquery = trans_param.ja_query_ref_->get_ref_stmt())) { + OB_ISNULL(subquery = trans_param.ja_query_ref_->get_ref_stmt()) || + OB_ISNULL(origin_subquery = subquery)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid transform params", K(ret), K(trans_param.ja_query_ref_)); } else if (!ObOptimizerUtil::find_item(stmt->get_subquery_exprs(), query_ref)) { @@ -308,16 +310,24 @@ int ObTransformAggrSubquery::do_aggr_first_transform(ObDMLStmt *&stmt, // skip } else if (trans_param.upper_filters_.count() > 0 && use_outer_join(trans_param.pullup_flag_)) { // skip - } else if (!trans_param.limit_for_exists_ && trans_param.limit_value_ > 0 && + } else if (trans_param.exists_to_aggr_ && trans_param.nested_conditions_.empty()) { + // skip + } else if (trans_param.limit_to_aggr_ && OB_FAIL(convert_limit_as_aggr(subquery, trans_param))) { LOG_WARN("failed to transform subquery with limit"); - } else if (OB_FAIL(fill_query_refs(stmt, expr, trans_param))) { + } else if (trans_param.exists_to_aggr_ && + OB_FAIL(convert_exists_as_scalar_subquery(stmt, query_ref, subquery, trans_param))) { + LOG_WARN("failed to convert exists as scalar subquery", K(ret)); + } else if (trans_param.any_all_to_aggr_ && + OB_FAIL(convert_any_all_as_scalar_subquery(stmt, query_ref, subquery, trans_param))) { + LOG_WARN("failed to convert exists as scalar subquery", K(ret)); + } else if (OB_FAIL(fill_query_refs(stmt, expr->has_flag(CNT_ALIAS), trans_param))) { LOG_WARN("failed to fill query refs", K(ret)); } else if (OB_FAIL(transform_child_stmt(stmt, *subquery, trans_param))) { LOG_WARN("failed to transform subquery", K(ret)); } else if (OB_FAIL(transform_upper_stmt(*stmt, trans_param))) { LOG_WARN("failed to transform upper stmt", K(ret)); - } else if (OB_FAIL(add_trans_stmt_info(*subquery, AGGR_FIRST))) { + } else if (OB_FAIL(add_trans_stmt_info(*origin_subquery, AGGR_FIRST))) { LOG_WARN("failed add trans stmt info", K(ret)); } else { trans_happened = true; @@ -341,8 +351,7 @@ int ObTransformAggrSubquery::gather_transform_params(ObDMLStmt &stmt, if (OB_ISNULL(child_expr) || OB_ISNULL(root_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret), K(child_expr), K(root_expr)); - } else if (!child_expr->has_flag(CNT_SUB_QUERY) || (IS_SUBQUERY_COMPARISON_OP(child_expr->get_expr_type()) && - (child_expr->has_flag(IS_WITH_ANY) || child_expr->has_flag(IS_WITH_ALL) || aggr_first(pullup_strategy)))) { + } else if (!child_expr->has_flag(CNT_SUB_QUERY)) { // do nothing } else if (child_expr->is_query_ref_expr()) { TransformParam trans_param(pullup_strategy); @@ -364,14 +373,25 @@ int ObTransformAggrSubquery::gather_transform_params(ObDMLStmt &stmt, OPT_TRACE("hint reject transform"); } else if (aggr_first(pullup_strategy)) { OPT_TRACE("try aggregation first transform"); - if (OB_FAIL(check_aggr_first_validity(*trans_param.ja_query_ref_, - root_expr->has_flag(CNT_ALIAS), - trans_param.nested_conditions_, - trans_param.upper_filters_, - is_select_item_expr, - is_valid, - limit_value, - trans_param.equal_param_info_))) { + if (OB_FAIL(ObTransformUtils::find_parent_expr(root_expr, child_expr, trans_param.parent_expr_of_query_ref))) { + LOG_WARN("failed to find parent expr of subquery expr", K(ret)); + } else if (OB_ISNULL(trans_param.parent_expr_of_query_ref)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("find no parent expr of subquery expr", K(ret)); + } else if (OB_FAIL(check_aggr_first_validity(stmt, + *trans_param.ja_query_ref_, + root_expr->has_flag(CNT_ALIAS), + root_expr, + *trans_param.parent_expr_of_query_ref, + trans_param.nested_conditions_, + trans_param.upper_filters_, + is_select_item_expr, + is_valid, + limit_value, + trans_param.limit_to_aggr_, + trans_param.any_all_to_aggr_, + trans_param.exists_to_aggr_, + trans_param.equal_param_info_))) { LOG_WARN("failed to check subquery validity for aggr first", K(ret)); } else { trans_param.limit_for_exists_ = false; @@ -387,6 +407,7 @@ int ObTransformAggrSubquery::gather_transform_params(ObDMLStmt &stmt, } else if (OB_FAIL(check_join_first_validity(*trans_param.ja_query_ref_, root_expr->has_flag(CNT_ALIAS), is_exists_op(root_expr->get_expr_type()), + *trans_param.parent_expr_of_query_ref, IS_SUBQUERY_COMPARISON_OP(trans_param.parent_expr_of_query_ref->get_expr_type()), trans_param.not_null_const_, trans_param.limit_for_exists_, @@ -407,9 +428,9 @@ int ObTransformAggrSubquery::gather_transform_params(ObDMLStmt &stmt, } } else { // join-first ja can rewrite exists predicate (must be a root relation expr in where/having) - bool is_exists_filter = is_exists_op(child_expr->get_expr_type()) && - root_expr == child_expr && join_first(pullup_strategy); - if (is_exists_filter || !is_exists_op(child_expr->get_expr_type())) { + bool is_valid_exists_filter = aggr_first(pullup_strategy) || + (is_exists_op(child_expr->get_expr_type()) && root_expr == child_expr); + if (is_valid_exists_filter || !is_exists_op(child_expr->get_expr_type())) { for (int64_t i = 0; OB_SUCC(ret) && i < child_expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(gather_transform_params(stmt, root_expr, child_expr->get_param_expr(i), @@ -428,42 +449,78 @@ int ObTransformAggrSubquery::gather_transform_params(ObDMLStmt &stmt, * @brief ObTransformAggrSubquery::check_aggr_first_validity * check the valiaidty of the subquery */ -int ObTransformAggrSubquery::check_aggr_first_validity(ObQueryRefRawExpr &query_ref, +int ObTransformAggrSubquery::check_aggr_first_validity(ObDMLStmt &stmt, + ObQueryRefRawExpr &query_ref, const bool vector_assign, + ObRawExpr *root_expr, + ObRawExpr &parent_expr, ObIArray &nested_conditions, ObIArray &upper_filters, const bool is_select_item_expr, bool &is_valid, int64_t &limit_value, + bool &limit_to_aggr, + bool &any_all_to_aggr, + bool &exists_to_aggr, ObIArray &equal_param_info) { int ret = OB_SUCCESS; ObSelectStmt *subquery = NULL; bool has_rownum = false; bool has_ref_assign_user_var = false; - bool limit_to_aggr = false; bool has_equal_correlation = false; bool is_correlated = false; nested_conditions.reuse(); upper_filters.reuse(); is_valid = true; + bool is_group_single_set = false; + bool is_limit_single_set = false; + limit_to_aggr = false; + any_all_to_aggr = false; + exists_to_aggr = false; limit_value = -1; - if (OB_ISNULL(subquery = query_ref.get_ref_stmt())) { + uint64_t opt_version = 0; + bool check_match_index = true; + bool hint_allowed_transform = false; + if (OB_ISNULL(subquery = query_ref.get_ref_stmt()) || OB_ISNULL(stmt.get_query_ctx()) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("subquery is null", K(ret)); + } else if (OB_FALSE_IT(opt_version = stmt.get_query_ctx()->optimizer_features_enable_version_)) { } else if (OB_FAIL(check_nested_subquery(query_ref, is_valid))) { LOG_WARN("failed to check nested subquery", K(ret)); } else if (!is_valid) { OPT_TRACE("exec param reference another subquery"); // 0. check single set } else if (OB_FAIL(check_single_set_subquery(*subquery, - is_valid, - limit_to_aggr, + is_group_single_set, + is_limit_single_set, limit_value))) { LOG_WARN("failed to check is single set query", K(ret)); - } else if (!is_valid) { - OPT_TRACE("not single set query"); + } else if (is_limit_single_set && OB_FAIL(check_limit_single_set_validity(*subquery, + parent_expr, + limit_to_aggr, + equal_param_info))) { + LOG_WARN("failed to check select validity for limit 1", K(ret)); + } else if (opt_version >= COMPAT_VERSION_4_3_2 && is_select_item_expr && + OB_FAIL(check_can_trans_any_all_as_scalar_subquery(stmt, + subquery, + &parent_expr, + root_expr, + any_all_to_aggr))) { + LOG_WARN("failed to check can trans any all as aggr subquery", K(ret)); + } else if (opt_version >= COMPAT_VERSION_4_3_2 && is_select_item_expr && + OB_FAIL(check_can_trans_exists_as_scalar_subquery(query_ref, + parent_expr, + limit_value, + exists_to_aggr))) { + LOG_WARN("failed to check can trans exists as aggr subquery", K(ret)); + } else if (!is_group_single_set && !limit_to_aggr && !any_all_to_aggr && !exists_to_aggr) { + is_valid = false; + OPT_TRACE("not scalar subquery or equivalent scalar subquery"); // 1. check stmt components + } else if (!any_all_to_aggr && (IS_SUBQUERY_COMPARISON_OP(parent_expr.get_expr_type()) && + (parent_expr.has_flag(IS_WITH_ANY) || parent_expr.has_flag(IS_WITH_ALL)))) { + is_valid = false; } else if (subquery->has_rollup() || subquery->has_having() || NULL != subquery->get_limit_percent_expr() || @@ -520,9 +577,17 @@ int ObTransformAggrSubquery::check_aggr_first_validity(ObQueryRefRawExpr &query_ is_valid = false; OPT_TRACE("subquery`s outer/semi join condition is correlated"); // 6. check correlated join contiditons - } else if (OB_FAIL(check_subquery_conditions(query_ref, *subquery, nested_conditions, upper_filters, - is_select_item_expr || limit_to_aggr, - is_valid, has_equal_correlation))) { + } else if (OB_FALSE_IT(hint_allowed_transform = (subquery->get_stmt_hint().has_enable_hint(T_UNNEST) || + subquery->get_stmt_hint().has_enable_hint(T_AGGR_FIRST_UNNEST)))) { + } else if (OB_FALSE_IT(check_match_index = hint_allowed_transform ? false : + is_select_item_expr || limit_to_aggr)) { + } else if (OB_FAIL(check_subquery_conditions(query_ref, + *subquery, + nested_conditions, + upper_filters, + check_match_index, + is_valid, + has_equal_correlation))) { LOG_WARN("failed to check subquery conditions", K(ret)); } else if (!is_valid) { OPT_TRACE("subquery's condition is not valid"); @@ -530,10 +595,6 @@ int ObTransformAggrSubquery::check_aggr_first_validity(ObQueryRefRawExpr &query_ // transform limit 1 to aggr only if subquery has equal correlation is_valid = false; OPT_TRACE("subquery does not have euqal correlation condition"); - } else if (limit_to_aggr && OB_FAIL(check_subquery_select_for_limit_1(*subquery, - is_valid, - equal_param_info))) { - LOG_WARN("failed to check select validity for limit 1", K(ret)); } else if (!is_valid) { OPT_TRACE("select item is lob or const"); } else if (OB_FAIL(check_subquery_orderby(query_ref, is_valid))) { @@ -600,17 +661,24 @@ int ObTransformAggrSubquery::check_subquery_orderby(const ObQueryRefRawExpr &que } -int ObTransformAggrSubquery::check_subquery_select_for_limit_1(ObSelectStmt &subquery, - bool &is_valid, - ObIArray &equal_param_info) +int ObTransformAggrSubquery::check_limit_single_set_validity(const ObSelectStmt &subquery, + const ObRawExpr &parent_expr, + bool &is_valid, + ObIArray &equal_param_info) { int ret = OB_SUCCESS; // check select item for transform limit 1 to group by // 1. only one select item // 2. not lob or const // 3. same as the first expr in order by - is_valid = (1 == subquery.get_select_item_size()); - if (is_valid) { + is_valid = false; + if (1 != subquery.get_select_item_size()) { + // do nothing + } else if (is_exists_op(parent_expr.get_expr_type()) || + (IS_SUBQUERY_COMPARISON_OP(parent_expr.get_expr_type()) && ( + parent_expr.has_flag(IS_WITH_ANY) || parent_expr.has_flag(IS_WITH_ALL)))) { + // do nothing + } else { ObRawExpr *select_expr = NULL; if (OB_ISNULL(select_expr = subquery.get_select_item(0).expr_)) { ret = OB_ERR_UNEXPECTED; @@ -620,7 +688,7 @@ int ObTransformAggrSubquery::check_subquery_select_for_limit_1(ObSelectStmt &sub is_valid = false; } else if (subquery.has_order_by()) { ObStmtCompareContext context; - OrderItem& first_order = subquery.get_order_item(0); + const OrderItem& first_order = subquery.get_order_item(0); if (OB_ISNULL(first_order.expr_) || OB_ISNULL(subquery.get_query_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret)); @@ -635,10 +703,13 @@ int ObTransformAggrSubquery::check_subquery_select_for_limit_1(ObSelectStmt &sub LOG_WARN("failed to assign equal param info", K(ret)); } else { is_valid = true; + OPT_TRACE("can convert limit 1 to aggr"); } } else { is_valid = false; } + } else { + is_valid = true; } } return ret; @@ -813,13 +884,22 @@ int ObTransformAggrSubquery::choose_pullup_method(ObIArray &filters bool is_null_propagate = true; bool is_null_reject = false; bool is_scalar_aggr = false; + int64_t null_prop_array_size = 0; + bool need_check_null_prop = true; if (OB_ISNULL(query_ref) || OB_ISNULL(subquery = query_ref->get_ref_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params are invalid", K(ret), K(query_ref), K(subquery)); + } else if (OB_FALSE_IT(is_scalar_aggr = subquery->is_scala_group_by())) { + } else if (trans_param.any_all_to_aggr_ || trans_param.exists_to_aggr_) { + if (OB_FAIL(is_null_prop.prepare_allocate(1))) { + LOG_WARN("failed to prepare allocate case when array", K(ret)); + } else { + is_null_prop.at(0) = false; + need_check_null_prop = false; + is_null_propagate = false; + } } else if (OB_FAIL(is_null_prop.prepare_allocate(subquery->get_select_item_size()))) { LOG_WARN("failed to prepare allocate case when array", K(ret)); - } else { - is_scalar_aggr = subquery->is_scala_group_by(); } // 1. scalar group by must return one row // if join result is empty, we need deduce results for the scalar aggr items @@ -827,7 +907,7 @@ int ObTransformAggrSubquery::choose_pullup_method(ObIArray &filters // 2. normal group by, return zero or one row // if return zero, the main query gots null from the subquery // if return one, the main query gots real values from the subquery - for (int64_t i = 0; OB_SUCC(ret) && i < subquery->get_select_item_size(); ++i) { + for (int64_t i = 0; OB_SUCC(ret) && need_check_null_prop && i < subquery->get_select_item_size(); ++i) { ObRawExpr *expr = NULL; is_null_prop.at(i) = false; if (!is_scalar_aggr) { @@ -951,7 +1031,11 @@ int ObTransformAggrSubquery::transform_child_stmt(ObDMLStmt *stmt, } } if (OB_SUCC(ret)) { - if (OB_FAIL(subquery.formalize_stmt(ctx_->session_info_))) { + if (OB_FAIL(eliminate_redundant_aggregation_if_need(subquery, param))) { + LOG_WARN("failed to eliminate redundant aggregation if need", K(ret)); + } else if (OB_FAIL(eliminate_limit_if_need(subquery, param, false))) { + LOG_WARN("failed to eliminate limit if need", K(ret)); + } else if (OB_FAIL(subquery.formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize subquery", K(ret)); } } @@ -972,6 +1056,7 @@ int ObTransformAggrSubquery::transform_upper_stmt(ObDMLStmt &stmt, TransformPara ObSEArray view_columns; ObSEArray select_exprs; ObSEArray real_values; + ObRawExpr *real_parent_value = NULL; ObQueryRefRawExpr *query_expr = param.ja_query_ref_; ObIArray &pullup_conds = param.nested_conditions_; ObIArray &upper_filters = param.upper_filters_; @@ -998,18 +1083,40 @@ int ObTransformAggrSubquery::transform_upper_stmt(ObDMLStmt &stmt, TransformPara } if (OB_SUCC(ret)) { + ObSEArray from_exprs; + ObSEArray to_exprs; // 2. 推导原始的子查询计算结果 - if (OB_FAIL(ObTransformUtils::deduce_query_values(*ctx_, - stmt, - param.is_null_prop_, - param.not_null_expr_, - use_outer_join(param.pullup_flag_), - select_exprs, view_columns, real_values))) { - LOG_WARN("failed to deduce subquery output", K(ret)); - } else if (OB_FAIL(stmt.replace_relation_exprs(param.query_refs_, real_values))) { - LOG_WARN("failed to replace inner stmt expr", K(ret)); - // 3. 构造连接条件,连接视图 - } else if (OB_FAIL(ObTransformUtils::replace_exprs(select_exprs, view_columns, pullup_conds))) { + if (param.any_all_to_aggr_ || param.exists_to_aggr_) { + if (OB_FAIL(deduce_query_values_for_exists(*ctx_, + stmt, + param.not_null_expr_, + param.parent_expr_of_query_ref, + real_parent_value))) { + LOG_WARN("failed to deduce query values for exists", K(ret)); + } else if (OB_FAIL(from_exprs.push_back(param.parent_expr_of_query_ref))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (OB_FAIL(to_exprs.push_back(real_parent_value))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (OB_FAIL(stmt.replace_relation_exprs(from_exprs, to_exprs))) { + LOG_WARN("failed to replace inner stmt expr", K(ret)); + } + } else { + if (OB_FAIL(ObTransformUtils::deduce_query_values(*ctx_, + stmt, + param.is_null_prop_, + param.not_null_expr_, + use_outer_join(param.pullup_flag_), + select_exprs, view_columns, real_values))) { + LOG_WARN("failed to deduce subquery output", K(ret)); + } else if (OB_FAIL(stmt.replace_relation_exprs(param.query_refs_, real_values))) { + LOG_WARN("failed to replace inner stmt expr", K(ret)); + } + } + } + + if (OB_SUCC(ret)) { + // 3. 构造连接条件,连接视图 + if (OB_FAIL(ObTransformUtils::replace_exprs(select_exprs, view_columns, pullup_conds))) { LOG_WARN("failed to replace pullup conditions", K(ret)); } else if (OB_FAIL(ObTransformUtils::decorrelate(pullup_conds, query_expr->get_exec_params()))) { LOG_WARN("failed to decorrelation", K(ret)); @@ -1107,7 +1214,7 @@ int ObTransformAggrSubquery::transform_with_join_first(ObDMLStmt *&stmt, OB_FAIL(convert_limit_as_aggr(param.ja_query_ref_->get_ref_stmt(), param))) { LOG_WARN("fail to transform for limit"); - } else if (OB_FAIL(fill_query_refs(target_stmt, root_expr, param))) { + } else if (OB_FAIL(fill_query_refs(target_stmt, root_expr->has_flag(CNT_ALIAS), param))) { LOG_WARN("failed to fill query refs", K(ret)); } else if (OB_FAIL(get_trans_view(*target_stmt, view_stmt, @@ -1339,6 +1446,7 @@ int ObTransformAggrSubquery::check_stmt_valid(ObDMLStmt &stmt, bool &is_valid) int ObTransformAggrSubquery::check_join_first_validity(ObQueryRefRawExpr &query_ref, const bool is_vector_assign, const bool in_exists, + const ObRawExpr &parent_expr, const bool is_vector_cmp, ObIArray &constraints, bool &add_limit_constraints, @@ -1355,6 +1463,8 @@ int ObTransformAggrSubquery::check_join_first_validity(ObQueryRefRawExpr &query_ ObSEArray nested_conditions; ObSelectStmt *subquery = NULL; is_valid = true; + bool is_group_single_set = false; + bool is_limit_single_set = false; if (OB_ISNULL(subquery = query_ref.get_ref_stmt()) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->exec_ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("subquery is null", K(ret)); @@ -1364,12 +1474,13 @@ int ObTransformAggrSubquery::check_join_first_validity(ObQueryRefRawExpr &query_ OPT_TRACE("exec param reference another subquery"); // 0. check single set } else if (OB_FAIL(check_single_set_subquery(*subquery, - is_valid, - limit_to_aggr, + is_group_single_set, + is_limit_single_set, limit_value, !in_exists))) { LOG_WARN("failed to check is single set query", K(ret)); - } else if (!is_valid) { + } else if (!is_group_single_set && !is_limit_single_set) { + is_valid = false; OPT_TRACE("not single set query"); // 1. check stmt components } else if (subquery->get_group_expr_size() > 0 || @@ -1495,12 +1606,12 @@ int ObTransformAggrSubquery::check_join_first_validity(ObQueryRefRawExpr &query_ is_valid = false; LOG_TRACE("no correlated common comparsion condition found", K(is_valid), K(has_correlated_cond)); OPT_TRACE("no correlated common comparsion condition found"); - } else if (limit_to_aggr && OB_FAIL(check_join_first_condition_for_limit_1(query_ref, *subquery, is_valid))) { + } else if (is_limit_single_set && OB_FAIL(check_join_first_condition_for_limit_1(query_ref, *subquery, is_valid))) { LOG_WARN("failed to check condition for limit 1", K(ret)); } else if (!is_valid) { // do nothing - } else if (limit_to_aggr && - OB_FAIL(check_subquery_select_for_limit_1(*subquery, is_valid, equal_param_info))) { + } else if (is_limit_single_set && + OB_FAIL(check_limit_single_set_validity(*subquery, parent_expr, is_valid, equal_param_info))) { LOG_WARN("failed to check select validity for limit 1", K(ret)); } return ret; @@ -1916,14 +2027,14 @@ int ObTransformAggrSubquery::check_subquery_having(const ObQueryRefRawExpr &quer } int ObTransformAggrSubquery::check_single_set_subquery(const ObSelectStmt &subquery, - bool &is_valid, - bool &limit_to_aggr, + bool &group_single_set, + bool &limit_single_set, int64_t &limit_value, bool check_limit /*= true*/) { int ret = OB_SUCCESS; - is_valid = false; - limit_to_aggr = false; + group_single_set = false; + limit_single_set = false; bool valid_group_by = false; bool is_null_value = true; bool has_limit = false; @@ -1952,13 +2063,11 @@ int ObTransformAggrSubquery::check_single_set_subquery(const ObSelectStmt &subqu if (OB_FAIL(ret)) { } else if (valid_group_by) { // 1. subquery is a valid group by (with no limit or limit > 0); or - is_valid = !check_limit || !has_limit || (!is_null_value && limit_value >= 1); + group_single_set = !check_limit || !has_limit || (!is_null_value && limit_value >= 1); } else if (check_limit && !subquery.has_group_by()) { // 2. subquery is not group by but has limit 1 and is not with tie - limit_to_aggr = !is_null_value && limit_value == 1 && - !subquery.is_fetch_with_ties(); - is_valid = limit_to_aggr; - OPT_TRACE("limit 1 can be converted to aggr"); + limit_single_set = !is_null_value && limit_value == 1 && + !subquery.is_fetch_with_ties(); } return ret; } @@ -2241,15 +2350,15 @@ int ObTransformAggrSubquery::check_can_use_outer_join(TransformParam ¶m, } int ObTransformAggrSubquery::fill_query_refs(ObDMLStmt *stmt, - ObRawExpr *expr, + bool cnt_alias, TransformParam ¶m) { int ret = OB_SUCCESS; param.query_refs_.reuse(); - if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { + if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("params are invalid" ,K(ret), K(stmt), K(expr)); - } else if (expr->has_flag(CNT_ALIAS)) { + LOG_WARN("params are invalid" ,K(ret), K(stmt)); + } else if (cnt_alias) { if (stmt->is_update_stmt()) { if (OB_FAIL(static_cast(stmt)->get_vector_assign_values( param.ja_query_ref_, @@ -2354,7 +2463,7 @@ int ObTransformAggrSubquery::get_filters(ObDMLStmt &stmt, int ObTransformAggrSubquery::extract_no_rewrite_select_exprs(ObDMLStmt *&stmt) { int ret = OB_SUCCESS; - if (OB_ISNULL(stmt)) { + if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(stmt->get_query_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (stmt->is_select_stmt() && stmt->get_subquery_expr_size() > 0) { @@ -2552,48 +2661,51 @@ int ObTransformAggrSubquery::convert_limit_as_aggr(ObSelectStmt *subquery, } } - // Add constraints and remove limit - if (OB_SUCC(ret)) { - ObConstRawExpr* one_expr = NULL; - ObRawExpr* cmp_expr = NULL; - ObRawExpr* limit_expr = NULL; - if (OB_ISNULL(limit_expr = subquery->get_limit_expr())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected null", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, - ObIntType, 1, one_expr))) { - LOG_WARN("fail to build int expr", K(ret)); - } else if (already_has_group && - OB_FAIL(ObRawExprUtils::create_double_op_expr(*ctx_->expr_factory_, - ctx_->session_info_, - T_OP_GE, - cmp_expr, - limit_expr, - one_expr))) { - LOG_WARN("fail to build cmp expr"); - } else if (!already_has_group && - OB_FAIL(ObRawExprUtils::create_double_op_expr(*ctx_->expr_factory_, - ctx_->session_info_, - T_OP_EQ, - cmp_expr, - limit_expr, - one_expr))) { - LOG_WARN("fail to build cmp expr"); - } else if ( - OB_FAIL(ObTransformUtils::add_param_bool_constraint(ctx_, - cmp_expr, - true/*is_true*/))) { - LOG_WARN("failed to add constraints", K(ret)); - } else if (OB_FAIL(append(ctx_->equal_param_constraints_, trans_param.equal_param_info_))) { - LOG_WARN("append equal param info failed", K(ret)); - } else { - subquery->set_limit_offset(NULL, NULL); - } + if (OB_SUCC(ret) && + OB_FAIL(eliminate_limit_if_need(*subquery, trans_param, false))) { + LOG_WARN("failed to eliminate limit if need", K(ret)); } } return ret; } +int ObTransformAggrSubquery::eliminate_limit_if_need(ObSelectStmt &subquery, + TransformParam &trans_param, + bool in_exist) +{ + int ret = OB_SUCCESS; + ObConstRawExpr* one_expr = NULL; + ObRawExpr* cmp_expr = NULL; + ObRawExpr* limit_expr = NULL; + bool already_has_group = subquery.has_group_by(); + ObItemType cmp_type = (already_has_group || in_exist) ? T_OP_GE : T_OP_EQ; + if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_ISNULL(limit_expr = subquery.get_limit_expr())) { + // do nothing + } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx_->expr_factory_, + ObIntType, 1, one_expr))) { + LOG_WARN("fail to build int expr", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::create_double_op_expr(*ctx_->expr_factory_, + ctx_->session_info_, + cmp_type, + cmp_expr, + limit_expr, + one_expr))) { + LOG_WARN("fail to build cmp expr"); + } else if (OB_FAIL(ObTransformUtils::add_param_bool_constraint(ctx_, + cmp_expr, + true/*is_true*/))) { + LOG_WARN("failed to add constraints", K(ret)); + } else if (OB_FAIL(append(ctx_->equal_param_constraints_, trans_param.equal_param_info_))) { + LOG_WARN("append equal param info failed", K(ret)); + } else { + subquery.set_limit_offset(NULL, NULL); + } + return ret; +} + int ObTransformAggrSubquery::check_nested_subquery(ObQueryRefRawExpr &query_ref, bool &is_valid) { @@ -2612,4 +2724,296 @@ int ObTransformAggrSubquery::check_nested_subquery(ObQueryRefRawExpr &query_ref, } } return ret; +} + +// for any/all subqueries used as condition,some of them can be converted to exists subquery. +// furthermore, such exists subquery can be considered as a scalar subquery. e.g. +// select case when c1 = ANY(select c1 from t2) then 1 else 0 end from t1; +// ==> +// select case when exists (select c1 from t2 where t1.c1 = t2.c1) then 1 else 0 end from t1; +// ==> +// select case when 0 < (select count(*) from t2 where t1.c1 = t2.c1) then 1 else 0 end from t1; +int ObTransformAggrSubquery::check_can_trans_any_all_as_scalar_subquery(ObDMLStmt &stmt, + ObSelectStmt *subquery, + ObRawExpr *parent_expr, + ObRawExpr *root_expr, + bool &is_valid) +{ + int ret = OB_SUCCESS; + is_valid = false; + bool has_rownum = false; + if (OB_ISNULL(subquery) || OB_ISNULL(parent_expr) || OB_ISNULL(root_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (parent_expr->get_expr_type() != T_OP_SQ_EQ || !parent_expr->has_flag(IS_WITH_ANY)) { + // only pure equal correlated condition can be converted to aggr-first join form + } else if (OB_FAIL(ObTransformUtils::check_expr_used_as_condition(&stmt, + root_expr, + parent_expr, + is_valid))) { + LOG_WARN("failed to check expr as condition", K(ret)); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(ObTransformUtils::check_can_trans_any_all_as_exists(ctx_, + parent_expr, + true, + false, + is_valid))) { + LOG_WARN("failed to check can trans any all as exists", K(ret)); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(subquery->has_rownum(has_rownum))) { + LOG_WARN("failed to check subquery has rownum", K(ret)); + } else if (subquery->has_group_by() || + subquery->has_window_function() || + subquery->has_limit() || + subquery->has_sequence() || + subquery->is_set_stmt() || + subquery->is_hierarchical_query() || + has_rownum) { + is_valid = false; + } else { + OPT_TRACE("can convert any all as scalar subquery"); + } + return ret; +} + +// some exists subqueries can be considered as scalar subqueries, e.g. +// select exists (select 1 from t2 where t1.c1 = t2.c1) from t1; +// ==> +// select 0 < (select count(*) from t2 where t1.c1 = t2.c1) from t1; +int ObTransformAggrSubquery::check_can_trans_exists_as_scalar_subquery(ObQueryRefRawExpr &query_ref, + ObRawExpr &parent_expr, + int64_t limit_value, + bool &is_valid) +{ + int ret = OB_SUCCESS; + bool has_rownum = false; + is_valid = false; + ObSelectStmt *subquery = query_ref.get_ref_stmt(); + if (parent_expr.get_expr_type() != T_OP_EXISTS && parent_expr.get_expr_type() != T_OP_NOT_EXISTS) { + // do nothing + } else if (OB_ISNULL(subquery)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(subquery->has_rownum(has_rownum))) { + LOG_WARN("failed to check subquery has rownum", K(ret)); + } else if (subquery->has_group_by() || + subquery->has_window_function() || + NULL != subquery->get_limit_percent_expr() || + NULL != subquery->get_offset_expr() || + subquery->has_sequence() || + subquery->is_set_stmt() || + subquery->is_hierarchical_query() || + has_rownum) { + // do nothing + } else if (OB_NOT_NULL(subquery->get_limit_expr()) && limit_value < 1) { + // do nothing + } else { + is_valid = true; + OPT_TRACE("can convert exists as scalar subquery"); + } + return ret; +} + +int ObTransformAggrSubquery::convert_exists_as_scalar_subquery(ObDMLStmt *stmt, + ObQueryRefRawExpr *query_ref, + ObSelectStmt *subquery, + TransformParam &trans_param) +{ + int ret = OB_SUCCESS; + ObRawExpr *parent_expr = NULL; + ObAggFunRawExpr *count_expr = NULL; + ObItemType cmp_type = T_OP_GT; + ObRawExpr *cmp_expr = NULL; + ObConstRawExpr *zero_expr = NULL; + ObSEArray from_exprs; + ObSEArray to_exprs; + if (OB_ISNULL(query_ref) || OB_ISNULL(subquery) || OB_ISNULL(ctx_) || + OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(stmt) || + OB_ISNULL(parent_expr = trans_param.parent_expr_of_query_ref) || + (parent_expr->get_expr_type() != T_OP_EXISTS && parent_expr->get_expr_type() != T_OP_NOT_EXISTS)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param", K(ret)); + // 1. repalce subquery's select items as count(*) + } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_FUN_COUNT, count_expr))) { + LOG_WARN("create ObAggFunRawExpr failed", K(ret)); + } else if (OB_ISNULL(count_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("agg expr is null", K(ret), K(count_expr)); + } else if (OB_FAIL(count_expr->formalize(ctx_->session_info_))) { + LOG_WARN("failed to extract info", K(ret)); + } else if (OB_FALSE_IT(subquery->get_select_items().reset())) { + } else if (OB_FALSE_IT(query_ref->get_column_types().reset())) { + } else if (OB_FALSE_IT(query_ref->set_output_column(1))) { + } else if (OB_FAIL(query_ref->get_column_types().push_back(count_expr->get_result_type()))) { + LOG_WARN("failed to add result type", K(ret)); + } else if (OB_FAIL(ObTransformUtils::create_select_item(*ctx_->allocator_, + count_expr, + subquery))) { + LOG_WARN("failed to create select item", K(ret)); + } else if (OB_FAIL(subquery->add_agg_item(*count_expr))) { + LOG_WARN("failed to add agg item", K(ret)); + // 2. replace `exists (select .. from ..)` as `(select count(*) from ...) > 0` + } else if (OB_FALSE_IT(query_ref->set_is_set(false))) { + } else if (is_oracle_mode() && OB_FAIL(ObRawExprUtils::build_const_number_expr( + *ctx_->expr_factory_, + ObNumberType, + number::ObNumber::get_zero(), + zero_expr))) { + LOG_WARN("failed to build const one", K(ret)); + } else if (!is_oracle_mode() && OB_FAIL(ObRawExprUtils::build_const_int_expr( + *ctx_->expr_factory_, + ObIntType, + 0, + zero_expr))) { + LOG_WARN("failed to build const one", K(ret)); + } else if (OB_FALSE_IT(cmp_type = (parent_expr->get_expr_type() == T_OP_EXISTS) ? T_OP_GT : T_OP_LE)) { + } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(*ctx_->expr_factory_, + cmp_type, + query_ref, + zero_expr, + cmp_expr))) { + LOG_WARN("failed to build common binary op expr", K(ret)); + } else if (OB_ISNULL(cmp_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("agg expr is null", K(ret), K(count_expr)); + } else if (OB_FAIL(cmp_expr->formalize(ctx_->session_info_))) { + LOG_WARN("failed to formalize expr", K(ret)); + } else if (OB_FAIL(from_exprs.push_back(parent_expr))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (OB_FAIL(to_exprs.push_back(cmp_expr))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (OB_FAIL(stmt->replace_relation_exprs(from_exprs, to_exprs))) { + LOG_WARN("failed to replace inner stmt expr", K(ret)); + } else { + trans_param.parent_expr_of_query_ref = cmp_expr; + } + + if (OB_SUCC(ret) && + OB_FAIL(eliminate_limit_if_need(*subquery, trans_param, false))) { + LOG_WARN("failed to eliminate limit if need", K(ret)); + } + return ret; +} + +int ObTransformAggrSubquery::convert_any_all_as_scalar_subquery(ObDMLStmt *stmt, + ObQueryRefRawExpr *query_ref, + ObSelectStmt *&subquery, + TransformParam &trans_param) +{ + int ret = OB_SUCCESS; + ObRawExpr *parent_expr = trans_param.parent_expr_of_query_ref; + bool trans_happened = false; + ObSEArray from_exprs; + ObSEArray to_exprs; + trans_param.nested_conditions_.reset(); + if (OB_ISNULL(query_ref) || OB_ISNULL(subquery) || + OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(parent_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param", K(ret)); + } else if (OB_ISNULL(parent_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param", K(ret)); + } else if (OB_FAIL(ObTransformUtils::do_trans_any_all_as_exists(ctx_, + parent_expr, + NULL, + trans_happened))) { + LOG_WARN("failed to transform any all as exists", K(ret)); + } else if (OB_ISNULL(subquery = query_ref->get_ref_stmt())) { + // during the process of rewriting any/all as exists, it might be necessary to generate a SPJ view, + // and the subquery could change, which needs to be updated. + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param", K(ret)); + } else if (OB_FAIL(ObTransformUtils::get_correlated_conditions(query_ref->get_exec_params(), + subquery->get_condition_exprs(), + trans_param.nested_conditions_))) { + LOG_WARN("failed to get correlated conditions", K(ret)); + } else if (OB_FAIL(from_exprs.push_back(trans_param.parent_expr_of_query_ref))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (OB_FAIL(to_exprs.push_back(parent_expr))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (OB_FAIL(stmt->replace_relation_exprs(from_exprs, to_exprs))) { + LOG_WARN("failed to replace inner stmt expr", K(ret)); + } else if (OB_FALSE_IT(trans_param.parent_expr_of_query_ref = parent_expr)) { + } else if (OB_FAIL(convert_exists_as_scalar_subquery(stmt, + query_ref, + subquery, + trans_param))) { + LOG_WARN("failed to convert exists as scalar subquery", K(ret)); + } + return ret; +} + +// for exists subquery, case when judgement for left join can be simplified: +// select case when v.c1 is not null then v.count(*) else 0 end > 0 from t1 left join (select count(*), c1 from t2 group by c1) v on t1.c1 = v.c1; +// ==> +// select v.c1 is not null from t1 left join (select count(*), c1 from t2 group by c1) v on t1.c1 = v.c1; +// Note: when v.c1 is not null, it can certainly be inferred that v.count(*) > 0 +int ObTransformAggrSubquery::deduce_query_values_for_exists(ObTransformerCtx &ctx, + ObDMLStmt &stmt, + ObRawExpr *not_null_expr, + ObRawExpr *parent_expr_of_query_ref, + ObRawExpr *&real_parent_value) +{ + int ret = OB_SUCCESS; + ObRawExpr *left_side = NULL; + ObRawExpr *right_side = NULL; + ObItemType cmp_type = T_INVALID; + if (OB_ISNULL(not_null_expr) || OB_ISNULL(parent_expr_of_query_ref) || + OB_ISNULL(ctx.session_info_) || OB_ISNULL(ctx.expr_factory_) || + (parent_expr_of_query_ref->get_expr_type() != T_OP_GT && + parent_expr_of_query_ref->get_expr_type() != T_OP_LE) || + parent_expr_of_query_ref->get_param_count() != 2 || + OB_ISNULL(left_side = parent_expr_of_query_ref->get_param_expr(0)) || + OB_ISNULL(right_side = parent_expr_of_query_ref->get_param_expr(1)) || + !left_side->is_query_ref_expr() || !right_side->is_static_const_expr()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param", K(ret)); + } else if (OB_FALSE_IT(cmp_type = parent_expr_of_query_ref->get_expr_type())) { + } else if (OB_FAIL(ObRawExprUtils::build_is_not_null_expr(*ctx.expr_factory_, + not_null_expr, + cmp_type == T_OP_GT, + real_parent_value))) { + LOG_WARN("failed to add is not null", K(ret)); + } else if (OB_ISNULL(real_parent_value)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param", K(ret)); + } else if (OB_FAIL(real_parent_value->formalize(ctx.session_info_))) { + LOG_WARN("failed to formalize expr", K(ret)); + } + return ret; +} + +// for exists/any subquery, redundant aggregation of subquery can by simplified: +// select v.c1 is not null from t1 left join (select count(*), c1 from t2 group by c1) v on t1.c1 = v.c1; +// ==> +// select v.c1 is not null from t1 left join (select distinct c1 from t2) v on t1.c1 = v.c1; +int ObTransformAggrSubquery::eliminate_redundant_aggregation_if_need(ObSelectStmt &stmt, + TransformParam &trans_param) +{ + int ret = OB_SUCCESS; + if (!trans_param.any_all_to_aggr_ && !trans_param.exists_to_aggr_) { + // do nothing + } else { + stmt.get_group_exprs().reset(); + stmt.get_aggr_items().reset(); + stmt.assign_distinct(); + ObSEArray new_select_items; + for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_select_item_size(); ++i) { + SelectItem &select_item = stmt.get_select_item(i); + if (OB_ISNULL(select_item.expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param", K(ret)); + } else if (select_item.expr_->is_aggr_expr()) { + // do nothing + } else if (OB_FAIL(new_select_items.push_back(select_item))) { + LOG_WARN("failed to push back select item", K(ret)); + } + } + if (OB_SUCC(ret) && OB_FAIL(stmt.get_select_items().assign(new_select_items))) { + LOG_WARN("failed to assign select items", K(ret)); + } + } + return ret; } \ No newline at end of file diff --git a/src/sql/rewrite/ob_transform_aggr_subquery.h b/src/sql/rewrite/ob_transform_aggr_subquery.h index f264651f4f..dd0bfe4b11 100644 --- a/src/sql/rewrite/ob_transform_aggr_subquery.h +++ b/src/sql/rewrite/ob_transform_aggr_subquery.h @@ -60,13 +60,14 @@ private: */ struct TransformParam { TransformParam() : ja_query_ref_(NULL), nested_conditions_(), pullup_flag_(0), - not_null_expr_(NULL), parent_expr_of_query_ref(NULL) + not_null_expr_(NULL), parent_expr_of_query_ref(NULL), limit_for_exists_(false), + limit_value_(0), limit_to_aggr_(false), any_all_to_aggr_(false), exists_to_aggr_(false) {} TransformParam(int64_t trans_strategy) : ja_query_ref_(NULL), nested_conditions_(), pullup_flag_(trans_strategy), not_null_expr_(NULL), parent_expr_of_query_ref(NULL), limit_for_exists_(false), - limit_value_(0) + limit_value_(0), limit_to_aggr_(false), any_all_to_aggr_(false), exists_to_aggr_(false) {} ObQueryRefRawExpr *ja_query_ref_; // the ja query ref expr @@ -79,6 +80,9 @@ private: ObRawExpr *parent_expr_of_query_ref; // parent expr need to be modified for vector subquery comparison bool limit_for_exists_; int64_t limit_value_; + bool limit_to_aggr_; // convert limit 1 single set as scala groupby + bool any_all_to_aggr_; // convert any/all subquery as scala groupby + bool exists_to_aggr_; // convert exists subquery as scala groupby ObSEArray equal_param_info_; ObSEArray upper_filters_; // filters can be pulled up to upper stmt (aggr first) TO_STRING_KV(K_(ja_query_ref), @@ -89,6 +93,9 @@ private: K_(not_null_expr), K_(limit_for_exists), K_(limit_value), + K_(limit_to_aggr), + K_(any_all_to_aggr), + K_(exists_to_aggr), K_(equal_param_info), K_(upper_filters)); }; @@ -124,19 +131,25 @@ private: const bool is_select_item_expr, ObIArray ¶ms); - int check_aggr_first_validity(ObQueryRefRawExpr &query_ref, + int check_aggr_first_validity(ObDMLStmt &stmt, + ObQueryRefRawExpr &query_ref, const bool is_vector_assign, + ObRawExpr *root_expr, + ObRawExpr &parent_expr, ObIArray &nested_conditions, ObIArray &upper_filters, const bool is_select_item_expr, bool &is_valid, int64_t &limit_value, + bool &limit_to_aggr, + bool &any_all_to_aggr, + bool &exists_to_aggr, ObIArray &equal_param_info); int choose_pullup_method(ObIArray &conditions, TransformParam ¶m); - int fill_query_refs(ObDMLStmt *stmt, ObRawExpr *expr, TransformParam ¶m); + int fill_query_refs(ObDMLStmt *stmt, bool cnt_alias, TransformParam ¶m); int transform_child_stmt(ObDMLStmt *stmt, ObSelectStmt &subquery, @@ -170,6 +183,7 @@ private: int check_join_first_validity(ObQueryRefRawExpr &query_ref, const bool is_vector_assign, const bool in_exists, + const ObRawExpr &parent_expr, const bool is_vector_cmp, ObIArray &constraints, bool &add_limit_constraints, @@ -206,8 +220,8 @@ private: int rebuild_conditon(ObSelectStmt &stmt, ObSelectStmt &subquery); int check_single_set_subquery(const ObSelectStmt &subquery, - bool &is_valid, - bool &limit_to_aggr, + bool &group_single_set, + bool &limit_single_set, int64_t &limit_value, bool check_limit = true); @@ -226,7 +240,10 @@ private: int check_subquery_select(const ObQueryRefRawExpr &query_ref, bool &is_valid); int check_subquery_orderby(const ObQueryRefRawExpr &query_ref, bool &is_valid); - int check_subquery_select_for_limit_1(ObSelectStmt &subquery, bool &is_valid, ObIArray& equal_param_info); + int check_limit_single_set_validity(const ObSelectStmt &subquery, + const ObRawExpr &parent_expr, + bool &is_valid, + ObIArray& equal_param_info); int check_join_first_condition_for_limit_1(ObQueryRefRawExpr &query_ref, ObSelectStmt &subquery, @@ -278,6 +295,32 @@ private: ObHint* get_sub_unnest_hint(ObSelectStmt &subquery, int64_t pullup_strategy); ObItemType get_unnest_strategy(int64_t pullup_strategy); int check_nested_subquery(ObQueryRefRawExpr &query_ref, bool &is_valid); + int check_can_trans_any_all_as_scalar_subquery(ObDMLStmt &stmt, + ObSelectStmt *subquery, + ObRawExpr *parent_expr, + ObRawExpr *root_expr, + bool &is_valid); + int check_can_trans_exists_as_scalar_subquery(ObQueryRefRawExpr &query_ref, + ObRawExpr &parent_expr, + int64_t limit_value, + bool &is_valid); + int convert_exists_as_scalar_subquery(ObDMLStmt *stmt, + ObQueryRefRawExpr *query_ref, + ObSelectStmt *subquery, + TransformParam &trans_param); + int eliminate_limit_if_need(ObSelectStmt &subquery, + TransformParam &trans_param, + bool in_exist); + int convert_any_all_as_scalar_subquery(ObDMLStmt *stmt, + ObQueryRefRawExpr *query_ref, + ObSelectStmt *&subquery, + TransformParam &trans_param); + int deduce_query_values_for_exists(ObTransformerCtx &ctx, + ObDMLStmt &stmt, + ObRawExpr *not_null_expr, + ObRawExpr *parent_expr_of_query_ref, + ObRawExpr *&real_parent_value); + int eliminate_redundant_aggregation_if_need(ObSelectStmt &stmt, TransformParam &trans_param); private: common::ObSEArray no_rewrite_exprs_; diff --git a/src/sql/rewrite/ob_transform_simplify_subquery.cpp b/src/sql/rewrite/ob_transform_simplify_subquery.cpp index f965b38c4f..49c1cb5d9e 100644 --- a/src/sql/rewrite/ob_transform_simplify_subquery.cpp +++ b/src/sql/rewrite/ob_transform_simplify_subquery.cpp @@ -341,7 +341,7 @@ int ObTransformSimplifySubquery::do_transform_not_expr(ObRawExpr *&expr, bool &t ObOpRawExpr *new_op_expr = NULL; ObSubQueryKey key_flag = param->has_flag(IS_WITH_ALL) ? T_WITH_ANY : T_WITH_ALL; - ObItemType new_type = get_opposite_expr_type(expr_type); + ObItemType new_type = ObTransformUtils::get_opposite_sq_cmp_type(expr_type); // 1. not col = all subquery can not be transformed // 2. not col != any subquery can not be transformed // 3. item type with T_INVALID can not be transformed @@ -371,36 +371,6 @@ int ObTransformSimplifySubquery::do_transform_not_expr(ObRawExpr *&expr, bool &t return ret; } -ObItemType ObTransformSimplifySubquery::get_opposite_expr_type(ObItemType item_type) -{ - ObItemType new_item_type = T_INVALID; - switch (item_type) { - case T_OP_SQ_EQ: - new_item_type = T_OP_SQ_NE; - break; - case T_OP_SQ_NE: - new_item_type = T_OP_SQ_EQ; - break; - case T_OP_SQ_GE: - new_item_type = T_OP_SQ_LT; - break; - case T_OP_SQ_GT: - new_item_type = T_OP_SQ_LE; - break; - case T_OP_SQ_LE: - new_item_type = T_OP_SQ_GT; - break; - case T_OP_SQ_LT: - new_item_type = T_OP_SQ_GE; - break; - default: - new_item_type = T_INVALID; - break; - } - return new_item_type; -} - - int ObTransformSimplifySubquery::remove_redundant_select(ObDMLStmt *&stmt, bool &trans_happened) { @@ -1934,13 +1904,18 @@ int ObTransformSimplifySubquery::try_trans_any_all_as_exists(ObDMLStmt *stmt, ret = OB_ERR_UNEXPECTED; LOG_WARN("params have null", K(ret), K(stmt), K(expr)); } else if (IS_SUBQUERY_COMPARISON_OP(expr->get_expr_type())) { - if (OB_FAIL(check_can_trans_as_exists(expr, is_bool_expr, is_valid))) { + if (OB_FAIL(ObTransformUtils::check_can_trans_any_all_as_exists(ctx_, + expr, + is_bool_expr, + true, + is_valid))) { LOG_WARN("failed to check in can tras as exists", K(ret)); } else if (!is_valid) { // do nothing - } else if (OB_FAIL(do_trans_any_all_as_exists(expr, - not_null_ctx, - is_happened))) { + } else if (OB_FAIL(ObTransformUtils::do_trans_any_all_as_exists(ctx_, + expr, + not_null_ctx, + is_happened))) { LOG_WARN("failed to do trans any all as exists", K(ret)); } else { trans_happened |= is_happened; @@ -2010,339 +1985,6 @@ int ObTransformSimplifySubquery::try_trans_any_all_as_exists(ObDMLStmt *stmt, return ret; } -int ObTransformSimplifySubquery::do_trans_any_all_as_exists(ObRawExpr *&expr, - ObNotNullContext *not_null_ctx, - bool &trans_happened) -{ - int ret = OB_SUCCESS; - ObRawExprFactory* expr_factory = NULL; - ObSelectStmt *right_stmt = NULL; - ObRawExpr *left_hand = NULL; - ObQueryRefRawExpr *right_hand = NULL; - ObSEArray left_exprs; - ObOpRawExpr* exists_expr = NULL; - ObItemType cmp_type = T_INVALID; - ObSEArray constraints; - ObSEArray or_exprs; - trans_happened = false; - - if (OB_ISNULL(ctx_) || - OB_ISNULL(expr_factory = ctx_->expr_factory_) || - OB_ISNULL(ctx_->session_info_) || - OB_ISNULL(left_hand = expr->get_param_expr(0)) || - OB_ISNULL(expr->get_param_expr(1)) || - OB_UNLIKELY(!expr->get_param_expr(1)->is_query_ref_expr())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("NULL pointer Error", KP_(ctx), K(ret)); - } else if (OB_FALSE_IT(right_hand = - static_cast(expr->get_param_expr(1)))) { - } else if (OB_FAIL(prepare_trans_any_all_as_exists(right_hand, right_stmt))) { - LOG_WARN("failed to prepare trans any all as exists", K(ret)); - } else if (T_OP_ROW != left_hand->get_expr_type() && - OB_FAIL(left_exprs.push_back(left_hand))) { - LOG_WARN("failed to push back expr", K(ret)); - } else if (T_OP_ROW == left_hand->get_expr_type() && - OB_FAIL(append(left_exprs, static_cast(left_hand)->get_param_exprs()))) { - LOG_WARN("failed to append exprs", K(ret)); - } else if (OB_ISNULL(right_stmt) || - OB_UNLIKELY(left_exprs.count() != right_stmt->get_select_item_size())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("select item size not equal to in expr size", K(left_exprs.count()), - K(right_stmt->get_select_item_size())); - } else { - ObNotNullContext right_null_ctx(*ctx_, right_stmt); - if (expr->has_flag(IS_WITH_ALL) && - OB_FAIL(right_null_ctx.generate_stmt_context(NULLABLE_SCOPE::NS_TOP))) { - LOG_WARN("failed to generate stmt context", K(ret)); - } - for (int64_t i = 0; OB_SUCC(ret) && i < left_exprs.count(); ++i) { - ObOpRawExpr* cmp_expr = NULL; - ObRawExpr* left_expr = NULL; - ObRawExpr* exec_param = NULL; - ObRawExpr* op_expr = NULL; - if (OB_ISNULL(left_expr = left_exprs.at(i)) || - OB_ISNULL(right_stmt->get_select_item(i).expr_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(ret), K(left_expr)); - } else if (OB_FAIL(ObRawExprUtils::get_exec_param_expr(*expr_factory, - right_hand, - left_expr, - exec_param))) { - LOG_WARN("failed to get exec param expr", K(ret)); - } else if (OB_FAIL(query_cmp_to_exists_value_cmp(expr->get_expr_type(), - expr->has_flag(IS_WITH_ALL), - cmp_type))) { - LOG_WARN("failed to get query cmp to value cmp type", K(ret)); - } else if (OB_FAIL(expr_factory->create_raw_expr(cmp_type, cmp_expr))) { - LOG_WARN("failed to create raw expr", K(ret)); - } else if (OB_ISNULL(cmp_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(ret), K(left_expr)); - } else if (OB_FAIL(cmp_expr->set_param_exprs(exec_param, - right_stmt->get_select_item(i).expr_))) { - LOG_WARN("failed to set param exprs", K(ret)); - } else if (OB_FAIL(cmp_expr->formalize(ctx_->session_info_))) { - LOG_WARN("failed to formalize cmp expr", K(ret)); - } else if (OB_FAIL(cmp_expr->pull_relation_id())) { - LOG_WARN("failed to pull relation id", K(ret)); - } else if (expr->has_flag(IS_WITH_ALL)) { - ObRawExpr* left_is_null_expr = NULL; - ObRawExpr* right_is_null_expr = NULL; - ObRawExpr* or_expr = NULL; - bool is_not_null = false; - constraints.reuse(); - or_exprs.reuse(); - if (OB_FAIL(or_exprs.push_back(cmp_expr))) { - LOG_WARN("failed to push back or expr"); - } else if (not_null_ctx != NULL && - OB_FAIL(ObTransformUtils::is_expr_not_null(*not_null_ctx, - left_expr, - is_not_null, - &constraints))) { - LOG_WARN("failed to check whether expr is nullable", K(ret)); - } else if (is_not_null && - OB_FAIL(ObTransformUtils::add_param_not_null_constraint(*ctx_, constraints))) { - LOG_WARN("failed to add param not null constraint", K(ret)); - } else if (!is_not_null && - OB_FAIL(ObRawExprUtils::build_is_not_null_expr(*expr_factory, - exec_param, - false, - left_is_null_expr))) { - LOG_WARN("failed to build is not null expr", K(ret)); - } else if (!is_not_null && - OB_FAIL(or_exprs.push_back(left_is_null_expr))) { - LOG_WARN("failed to push back expr", K(ret)); - } else if (OB_FALSE_IT(is_not_null = false)) { - } else if (OB_FALSE_IT(constraints.reuse())) { - } else if (OB_FAIL(ObTransformUtils::is_expr_not_null(right_null_ctx, - right_stmt->get_select_item(i).expr_, - is_not_null, - &constraints))) { - LOG_WARN("failed to check whether expr is nullable", K(ret)); - } else if (is_not_null && - OB_FAIL(ObTransformUtils::add_param_not_null_constraint(*ctx_, constraints))) { - LOG_WARN("failed to add param not null constraint", K(ret)); - } else if (!is_not_null && - OB_FAIL(ObRawExprUtils::build_is_not_null_expr(*expr_factory, - right_stmt->get_select_item(i).expr_, - false, - right_is_null_expr))) { - LOG_WARN("failed to build is not null expr", K(ret)); - } else if (!is_not_null && - OB_FAIL(or_exprs.push_back(right_is_null_expr))) { - LOG_WARN("failed to push back expr", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::build_or_exprs(*expr_factory, - or_exprs, - or_expr))) { - LOG_WARN("failed to build or exprs", K(ret)); - } else if (OB_ISNULL(or_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(ret), K(or_expr)); - } else if (OB_FAIL(or_expr->formalize(ctx_->session_info_))) { - LOG_WARN("failed to formalize expr", K(ret)); - } else if (OB_FAIL(or_expr->pull_relation_id())) { - LOG_WARN("failed to pull releation id", K(ret)); - } else { - op_expr = or_expr; - } - } else { - op_expr = cmp_expr; - } - - if (OB_SUCC(ret) && OB_FAIL(right_stmt->get_condition_exprs().push_back(op_expr))) { - LOG_WARN("failed to push back op expr", K(ret)); - } - } - } - - if (OB_FAIL(ret)) { - } else if (OB_FAIL(expr_factory->create_raw_expr(expr->has_flag(IS_WITH_ALL) - ? T_OP_NOT_EXISTS : T_OP_EXISTS, - exists_expr))) { - LOG_WARN("failed to create raw expr"); - } else if (OB_FAIL(OB_ISNULL(exists_expr))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(exists_expr)); - } else if (OB_FAIL(exists_expr->set_param_expr(right_hand))) { - LOG_WARN("failed to set param expr", K(ret)); - } else if (OB_FAIL(exists_expr->formalize(ctx_->session_info_))) { - LOG_WARN("failed to formalize expr", K(ret)); - } else { - expr = exists_expr; - trans_happened = true; - } - - return ret; -} - -int ObTransformSimplifySubquery::check_can_trans_as_exists(ObRawExpr* expr, bool is_bool_expr, bool& is_valid) -{ - int ret = OB_SUCCESS; - ObQueryRefRawExpr* right_hand = NULL; - ObRawExpr* left_hand = NULL; - bool dummy = false; - is_valid = false; - if (OB_ISNULL(expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("params have null", K(ret), K(expr)); - } else if (!is_bool_expr || - !IS_SUBQUERY_COMPARISON_OP(expr->get_expr_type()) || - (!expr->has_flag(IS_WITH_ALL) && - !expr->has_flag(IS_WITH_ANY))) { - // do nothing - } else if (OB_UNLIKELY(expr->get_param_count() != 2) || - OB_ISNULL(left_hand = expr->get_param_expr(0)) || - OB_ISNULL(expr->get_param_expr(1)) || - OB_UNLIKELY(!expr->get_param_expr(1)->is_query_ref_expr())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("param expr is null", K(ret)); - } else if (left_hand->has_flag(CNT_SUB_QUERY)) { - // do nothing - } else if (T_OP_ROW == left_hand->get_expr_type() && - (!(expr->get_expr_type() == T_OP_SQ_EQ && expr->has_flag(IS_WITH_ANY)) && - !(expr->get_expr_type() == T_OP_SQ_NE && expr->has_flag(IS_WITH_ALL)))) { - // do nothing - } else if (OB_FALSE_IT(right_hand = static_cast(expr->get_param_expr(1)))) { - } else if (right_hand->get_ref_count() > 1) { - // do nothing - } else if (OB_FAIL(check_stmt_can_trans_as_exists(right_hand->get_ref_stmt(), - !right_hand->get_exec_params().empty(), - dummy, - is_valid))) { - LOG_WARN("failed to check stmt can trans as exists", K(ret)); - } - return ret; -} - -int ObTransformSimplifySubquery::check_stmt_can_trans_as_exists(ObSelectStmt *stmt, - bool is_correlated, - bool &match_index, - bool &is_valid) -{ - int ret = OB_SUCCESS; - bool contain_rownum = false; - is_valid = false; - match_index = false; - if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(stmt->get_query_ctx())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("child stmt is null", K(ret)); - } else if (OB_FAIL(stmt->has_rownum(contain_rownum))) { - LOG_WARN("failed to check child statement contain rownum", K(ret)); - } else if (contain_rownum || - stmt->has_limit()) { - // do nothing - } else if (stmt->is_set_stmt()) { - bool has_index_matched = false; - if (stmt->is_recursive_union()) { - } else if (stmt->get_set_op() == ObSelectStmt::EXCEPT) { - if (OB_UNLIKELY(stmt->get_set_query().empty())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get except set query is empty", K(ret)); - } else if (OB_FAIL(SMART_CALL(check_stmt_can_trans_as_exists(stmt->get_set_query(0), - is_correlated, - has_index_matched, - is_valid)))) { - LOG_WARN("failted to check stmt can trans as exists", K(ret)); - } else { - match_index = has_index_matched; - is_valid = has_index_matched && is_valid; - } - } else { - is_valid = true; - for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < stmt->get_set_query().count(); ++i) { - has_index_matched = false; - if (OB_FAIL(SMART_CALL(check_stmt_can_trans_as_exists(stmt->get_set_query(i), - is_correlated, - has_index_matched, - is_valid)))) { - LOG_WARN("failted to check stmt can trans as exists", K(ret)); - } else if (has_index_matched) { - match_index = has_index_matched; - } - } - if (OB_SUCC(ret)) { - is_valid = match_index && is_valid; - } - } - } else if (stmt->is_contains_assignment() || - stmt->is_hierarchical_query() || - stmt->has_window_function() || - stmt->has_rollup() || - (stmt->is_values_table_query() && - !ObTransformUtils::is_enable_values_table_rewrite(stmt->get_query_ctx()->optimizer_features_enable_version_))) { - LOG_TRACE("stmt not support trans in as exists", K(stmt->is_contains_assignment()), - K(stmt->is_hierarchical_query()), K(stmt->has_window_function()), - K(stmt->has_rollup()), K(stmt->is_values_table_query())); - } else if (is_correlated) { - is_valid = true; - } else if (stmt->has_group_by() || - stmt->has_having()) { - // do nothing - } else if (0 == stmt->get_from_item_size()) { - is_valid = true; - } else { - ObArenaAllocator alloc; - EqualSets &equal_sets = ctx_->equal_sets_; - ObSEArray const_exprs; - if (OB_FAIL(stmt->get_stmt_equal_sets(equal_sets, alloc, true))) { - LOG_WARN("failed to get stmt equal sets", K(ret)); - } else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(stmt->get_condition_exprs(), - const_exprs))) { - LOG_WARN("failed to compute const equivalent exprs", K(ret)); - } else { - ObRawExpr *sel_expr = NULL; - for (int64_t i = 0; OB_SUCC(ret) && !is_valid && i < stmt->get_select_item_size(); ++i) { - if (OB_ISNULL(sel_expr = stmt->get_select_item(i).expr_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("select expr is NULL", K(ret)); - } else if (!sel_expr->is_column_ref_expr()) { - } else if (OB_FAIL(ObTransformUtils::is_match_index(ctx_->sql_schema_guard_, - stmt, - static_cast(sel_expr), - is_valid, - &equal_sets, - &const_exprs))) { - LOG_WARN("failed to check is match index prefix", K(ret)); - } else if (is_valid) { - match_index = true; - } - } - } - equal_sets.reuse(); - } - return ret; -} - -int ObTransformSimplifySubquery::query_cmp_to_exists_value_cmp(ObItemType type, bool is_with_all, ObItemType& new_type) -{ - int64_t ret = OB_SUCCESS; - if (is_with_all) { - type = get_opposite_expr_type(type); - } - ret = ObTransformUtils::query_cmp_to_value_cmp(type, new_type); - return ret; -} - -int ObTransformSimplifySubquery::prepare_trans_any_all_as_exists(ObQueryRefRawExpr* right_hand, ObSelectStmt *&trans_stmt) -{ - int ret = OB_SUCCESS; - trans_stmt = NULL; - if (OB_ISNULL(right_hand) || - OB_ISNULL(trans_stmt = right_hand->get_ref_stmt())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to prepare trans any all as exists", K(ret)); - } else if (trans_stmt->is_spj()) { - } else if (OB_FAIL(ObTransformUtils::create_stmt_with_generated_table(ctx_, - trans_stmt, - trans_stmt))) { - LOG_WARN("failed to create stmt with generated table", K(ret)); - } else { - right_hand->set_ref_stmt(trans_stmt); - } - - return ret; -} - int ObTransformSimplifySubquery::transform_any_all_as_exists(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; diff --git a/src/sql/rewrite/ob_transform_simplify_subquery.h b/src/sql/rewrite/ob_transform_simplify_subquery.h index 2d7644643c..f2142422fd 100644 --- a/src/sql/rewrite/ob_transform_simplify_subquery.h +++ b/src/sql/rewrite/ob_transform_simplify_subquery.h @@ -54,8 +54,6 @@ private: JoinedTable *join_table, bool &trans_happened); - ObItemType get_opposite_expr_type(ObItemType item_type); - int add_limit_for_exists_subquery(ObDMLStmt *stmt,bool &trans_happened); int recursive_add_limit_for_exists_expr(ObRawExpr *expr, bool &trans_happened); @@ -200,17 +198,7 @@ private: ObNotNullContext *not_null_ctx, bool is_bool_expr, bool &trans_happened); - int do_trans_any_all_as_exists(ObRawExpr *&expr, - ObNotNullContext *not_null_ctx, - bool &trans_happened); - int check_can_trans_as_exists(ObRawExpr* expr, bool is_bool_expr, bool &is_valid); - int check_stmt_can_trans_as_exists(ObSelectStmt *stmt, - bool is_correlated, - bool &match_index, - bool &is_valid); - int query_cmp_to_exists_value_cmp(ObItemType type, bool is_with_all, ObItemType& new_type); int add_limit_for_any_all_subquery(ObRawExpr *stmt,bool &trans_happened); - int prepare_trans_any_all_as_exists(ObQueryRefRawExpr* expr, ObSelectStmt *&trans_stmt); int transform_any_all_as_exists(ObDMLStmt *stmt, bool &trans_happened); int transform_any_all_as_exists_joined_table(ObDMLStmt* stmt, TableItem *table, diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index 0e888831c8..0a8bd750b5 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -16258,5 +16258,512 @@ int ObTransformUtils::check_expr_eq_zero(ObExecContext *ctx, return ret; } +int ObTransformUtils::check_expr_used_as_condition(ObDMLStmt *stmt, + ObRawExpr *root_expr, + ObRawExpr *expr, + bool &used_as_condition) +{ + int ret = OB_SUCCESS; + bool parent_as_condition = false; + used_as_condition = false; + ObRawExpr *cur_expr = root_expr; + if (OB_ISNULL(stmt) || OB_ISNULL(root_expr) || OB_ISNULL(expr) || OB_ISNULL(cur_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret), K(stmt), K(root_expr), K(expr)); + } else if (expr->get_ref_count() > 1) { + // do nothing + // if expr is shared, it is difficult to check its usage globally for now + } else if (ObOptimizerUtil::find_item(stmt->get_condition_exprs(), cur_expr)) { + parent_as_condition = true; + } else if (stmt->is_select_stmt() && ObOptimizerUtil::find_item( + static_cast(stmt)->get_having_exprs(), cur_expr)) { + parent_as_condition = true; + } + if (OB_SUCC(ret)) { + if (OB_FAIL(inner_check_expr_used_as_condition(cur_expr, + expr, + parent_as_condition, + used_as_condition))) { + LOG_WARN("failed to check expr used as condition", K(ret)); + } + } + return ret; +} + +int ObTransformUtils::inner_check_expr_used_as_condition(ObRawExpr *cur_expr, + ObRawExpr *expr, + bool parent_as_condition, + bool &used_as_condition) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(expr) || OB_ISNULL(cur_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret), K(expr)); + } else if (cur_expr == expr) { + used_as_condition = parent_as_condition; + } else if (cur_expr->get_expr_type() == T_OP_AND || cur_expr->get_expr_type() == T_OP_OR) { + // keep parent_as_condition unchanged + } else { + parent_as_condition = false; + } + + if (OB_SUCC(ret)) { + if (cur_expr->is_case_op_expr()) { + ObCaseOpRawExpr *case_expr = static_cast(cur_expr); + ObSEArray then_else_exprs; + if (OB_FAIL(append(then_else_exprs, case_expr->get_then_param_exprs()))) { + LOG_WARN("failed to append array", K(ret)); + } else if (OB_FAIL(then_else_exprs.push_back(case_expr->get_default_param_expr()))) { + LOG_WARN("failed to push back default param expr", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && !used_as_condition && i < case_expr->get_when_expr_size(); i++) { + bool tmp_used_as_condition = false; + if (OB_FAIL(SMART_CALL(inner_check_expr_used_as_condition(case_expr->get_when_param_expr(i), + expr, + true, + tmp_used_as_condition)))) { + LOG_WARN("failed to inner check expr used as condition", K(ret)); + } else if (tmp_used_as_condition) { + used_as_condition = true; + } + } + for (int64_t i = 0; OB_SUCC(ret) && !used_as_condition && i < then_else_exprs.count(); i++) { + bool tmp_used_as_condition = false; + if (OB_FAIL(SMART_CALL(inner_check_expr_used_as_condition(then_else_exprs.at(i), + expr, + true, + tmp_used_as_condition)))) { + LOG_WARN("failed to inner check expr used as condition", K(ret)); + } else if (tmp_used_as_condition) { + used_as_condition = true; + } + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && !used_as_condition && i < cur_expr->get_param_count(); i++) { + bool tmp_used_as_condition = false; + if (OB_FAIL(SMART_CALL(inner_check_expr_used_as_condition(cur_expr->get_param_expr(i), + expr, + parent_as_condition, + tmp_used_as_condition)))) { + LOG_WARN("failed to inner check expr used as condition", K(ret)); + } else if (tmp_used_as_condition) { + used_as_condition = true; + } + } + } + } + return ret; +} + +int ObTransformUtils::check_can_trans_any_all_as_exists(ObTransformerCtx *ctx, + ObRawExpr* expr, + bool used_as_condition, + bool need_match_index, + bool& is_valid) +{ + int ret = OB_SUCCESS; + ObQueryRefRawExpr* right_hand = NULL; + ObRawExpr* left_hand = NULL; + bool dummy = false; + is_valid = false; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("params have null", K(ret), K(expr)); + } else if (!used_as_condition || + !IS_SUBQUERY_COMPARISON_OP(expr->get_expr_type()) || + (!expr->has_flag(IS_WITH_ALL) && + !expr->has_flag(IS_WITH_ANY))) { + // do nothing + } else if (OB_UNLIKELY(expr->get_param_count() != 2) || + OB_ISNULL(left_hand = expr->get_param_expr(0)) || + OB_ISNULL(expr->get_param_expr(1)) || + OB_UNLIKELY(!expr->get_param_expr(1)->is_query_ref_expr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("param expr is null", K(ret)); + } else if (left_hand->has_flag(CNT_SUB_QUERY)) { + // do nothing + } else if (T_OP_ROW == left_hand->get_expr_type() && + (!(expr->get_expr_type() == T_OP_SQ_EQ && expr->has_flag(IS_WITH_ANY)) && + !(expr->get_expr_type() == T_OP_SQ_NE && expr->has_flag(IS_WITH_ALL)))) { + // do nothing + } else if (OB_FALSE_IT(right_hand = static_cast(expr->get_param_expr(1)))) { + } else if (right_hand->get_ref_count() > 1) { + // do nothing + } else if (OB_FAIL(check_stmt_can_trans_as_exists(right_hand->get_ref_stmt(), + ctx, + !right_hand->get_exec_params().empty(), + need_match_index, + dummy, + is_valid))) { + LOG_WARN("failed to check stmt can trans as exists", K(ret)); + } + return ret; +} + +int ObTransformUtils::check_stmt_can_trans_as_exists(ObSelectStmt *stmt, + ObTransformerCtx *ctx, + bool is_correlated, + bool need_match_index, + bool &match_index, + bool &is_valid) +{ + int ret = OB_SUCCESS; + bool contain_rownum = false; + is_valid = false; + match_index = false; + if (OB_ISNULL(stmt) || OB_ISNULL(ctx) || OB_ISNULL(stmt->get_query_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("child stmt is null", K(ret)); + } else if (OB_FAIL(stmt->has_rownum(contain_rownum))) { + LOG_WARN("failed to check child statement contain rownum", K(ret)); + } else if (contain_rownum || + stmt->has_limit()) { + // do nothing + } else if (stmt->is_set_stmt()) { + bool has_index_matched = false; + if (stmt->is_recursive_union()) { + } else if (stmt->get_set_op() == ObSelectStmt::EXCEPT) { + if (OB_UNLIKELY(stmt->get_set_query().empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get except set query is empty", K(ret)); + } else if (OB_FAIL(SMART_CALL(check_stmt_can_trans_as_exists(stmt->get_set_query(0), + ctx, + is_correlated, + need_match_index, + has_index_matched, + is_valid)))) { + LOG_WARN("failted to check stmt can trans as exists", K(ret)); + } else { + match_index = has_index_matched; + is_valid = (!need_match_index || has_index_matched) && is_valid; + } + } else { + is_valid = true; + for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < stmt->get_set_query().count(); ++i) { + has_index_matched = false; + if (OB_FAIL(SMART_CALL(check_stmt_can_trans_as_exists(stmt->get_set_query(i), + ctx, + is_correlated, + need_match_index, + has_index_matched, + is_valid)))) { + LOG_WARN("failted to check stmt can trans as exists", K(ret)); + } else if (has_index_matched) { + match_index = has_index_matched; + } + } + if (OB_SUCC(ret)) { + is_valid = (!need_match_index || match_index) && is_valid; + } + } + } else if (stmt->is_contains_assignment() || + stmt->is_hierarchical_query() || + stmt->has_window_function() || + stmt->has_rollup() || + (stmt->is_values_table_query() && + !ObTransformUtils::is_enable_values_table_rewrite(stmt->get_query_ctx()->optimizer_features_enable_version_))) { + LOG_TRACE("stmt not support trans in as exists", K(stmt->is_contains_assignment()), + K(stmt->is_hierarchical_query()), K(stmt->has_window_function()), + K(stmt->has_rollup()), K(stmt->is_values_table_query())); + } else if (is_correlated) { + is_valid = true; + } else if (stmt->has_group_by() || + stmt->has_having()) { + // do nothing + } else if (0 == stmt->get_from_item_size()) { + is_valid = true; + } else if (!need_match_index) { + is_valid = true; + } else { + ObArenaAllocator alloc; + EqualSets &equal_sets = ctx->equal_sets_; + ObSEArray const_exprs; + if (OB_FAIL(stmt->get_stmt_equal_sets(equal_sets, alloc, true))) { + LOG_WARN("failed to get stmt equal sets", K(ret)); + } else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(stmt->get_condition_exprs(), + const_exprs))) { + LOG_WARN("failed to compute const equivalent exprs", K(ret)); + } else { + ObRawExpr *sel_expr = NULL; + for (int64_t i = 0; OB_SUCC(ret) && !is_valid && i < stmt->get_select_item_size(); ++i) { + if (OB_ISNULL(sel_expr = stmt->get_select_item(i).expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("select expr is NULL", K(ret)); + } else if (!sel_expr->is_column_ref_expr()) { + } else if (OB_FAIL(ObTransformUtils::is_match_index(ctx->sql_schema_guard_, + stmt, + static_cast(sel_expr), + match_index, + &equal_sets, + &const_exprs))) { + LOG_WARN("failed to check is match index prefix", K(ret)); + } else if (match_index) { + is_valid = true; + } + } + } + equal_sets.reuse(); + } + return ret; +} + +int ObTransformUtils::do_trans_any_all_as_exists(ObTransformerCtx *ctx, + ObRawExpr *&expr, + ObNotNullContext *not_null_ctx, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + ObRawExprFactory* expr_factory = NULL; + ObSelectStmt *right_stmt = NULL; + ObRawExpr *left_hand = NULL; + ObQueryRefRawExpr *right_hand = NULL; + ObSEArray left_exprs; + ObOpRawExpr* exists_expr = NULL; + ObItemType cmp_type = T_INVALID; + ObSEArray constraints; + ObSEArray or_exprs; + trans_happened = false; + + if (OB_ISNULL(ctx) || + OB_ISNULL(expr_factory = ctx->expr_factory_) || + OB_ISNULL(ctx->session_info_) || + OB_ISNULL(left_hand = expr->get_param_expr(0)) || + OB_ISNULL(expr->get_param_expr(1)) || + OB_UNLIKELY(!expr->get_param_expr(1)->is_query_ref_expr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("NULL pointer Error", K(ret)); + } else if (OB_FALSE_IT(right_hand = + static_cast(expr->get_param_expr(1)))) { + } else if (OB_FAIL(prepare_trans_any_all_as_exists(ctx, right_hand, right_stmt))) { + LOG_WARN("failed to prepare trans any all as exists", K(ret)); + } else if (T_OP_ROW != left_hand->get_expr_type() && + OB_FAIL(left_exprs.push_back(left_hand))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (T_OP_ROW == left_hand->get_expr_type() && + OB_FAIL(append(left_exprs, static_cast(left_hand)->get_param_exprs()))) { + LOG_WARN("failed to append exprs", K(ret)); + } else if (OB_ISNULL(right_stmt) || + OB_UNLIKELY(left_exprs.count() != right_stmt->get_select_item_size())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("select item size not equal to in expr size", K(left_exprs.count()), + K(right_stmt->get_select_item_size())); + } else { + ObNotNullContext right_null_ctx(*ctx, right_stmt); + if (expr->has_flag(IS_WITH_ALL) && + OB_FAIL(right_null_ctx.generate_stmt_context(NULLABLE_SCOPE::NS_TOP))) { + LOG_WARN("failed to generate stmt context", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < left_exprs.count(); ++i) { + ObOpRawExpr* cmp_expr = NULL; + ObRawExpr* left_expr = NULL; + ObRawExpr* exec_param = NULL; + ObRawExpr* op_expr = NULL; + if (OB_ISNULL(left_expr = left_exprs.at(i)) || + OB_ISNULL(right_stmt->get_select_item(i).expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(left_expr)); + } else if (OB_FAIL(ObRawExprUtils::get_exec_param_expr(*expr_factory, + right_hand, + left_expr, + exec_param))) { + LOG_WARN("failed to get exec param expr", K(ret)); + } else if (OB_FAIL(query_cmp_to_exists_value_cmp(expr->get_expr_type(), + expr->has_flag(IS_WITH_ALL), + cmp_type))) { + LOG_WARN("failed to get query cmp to value cmp type", K(ret)); + } else if (OB_FAIL(expr_factory->create_raw_expr(cmp_type, cmp_expr))) { + LOG_WARN("failed to create raw expr", K(ret)); + } else if (OB_ISNULL(cmp_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(left_expr)); + } else if (OB_FAIL(cmp_expr->set_param_exprs(exec_param, + right_stmt->get_select_item(i).expr_))) { + LOG_WARN("failed to set param exprs", K(ret)); + } else if (OB_FAIL(cmp_expr->formalize(ctx->session_info_))) { + LOG_WARN("failed to formalize cmp expr", K(ret)); + } else if (OB_FAIL(cmp_expr->pull_relation_id())) { + LOG_WARN("failed to pull relation id", K(ret)); + } else if (expr->has_flag(IS_WITH_ALL)) { + ObRawExpr* left_is_null_expr = NULL; + ObRawExpr* right_is_null_expr = NULL; + ObRawExpr* or_expr = NULL; + bool is_not_null = false; + constraints.reuse(); + or_exprs.reuse(); + if (OB_FAIL(or_exprs.push_back(cmp_expr))) { + LOG_WARN("failed to push back or expr"); + } else if (not_null_ctx != NULL && + OB_FAIL(ObTransformUtils::is_expr_not_null(*not_null_ctx, + left_expr, + is_not_null, + &constraints))) { + LOG_WARN("failed to check whether expr is nullable", K(ret)); + } else if (is_not_null && + OB_FAIL(ObTransformUtils::add_param_not_null_constraint(*ctx, constraints))) { + LOG_WARN("failed to add param not null constraint", K(ret)); + } else if (!is_not_null && + OB_FAIL(ObRawExprUtils::build_is_not_null_expr(*expr_factory, + exec_param, + false, + left_is_null_expr))) { + LOG_WARN("failed to build is not null expr", K(ret)); + } else if (!is_not_null && + OB_FAIL(or_exprs.push_back(left_is_null_expr))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (OB_FALSE_IT(is_not_null = false)) { + } else if (OB_FALSE_IT(constraints.reuse())) { + } else if (OB_FAIL(ObTransformUtils::is_expr_not_null(right_null_ctx, + right_stmt->get_select_item(i).expr_, + is_not_null, + &constraints))) { + LOG_WARN("failed to check whether expr is nullable", K(ret)); + } else if (is_not_null && + OB_FAIL(ObTransformUtils::add_param_not_null_constraint(*ctx, constraints))) { + LOG_WARN("failed to add param not null constraint", K(ret)); + } else if (!is_not_null && + OB_FAIL(ObRawExprUtils::build_is_not_null_expr(*expr_factory, + right_stmt->get_select_item(i).expr_, + false, + right_is_null_expr))) { + LOG_WARN("failed to build is not null expr", K(ret)); + } else if (!is_not_null && + OB_FAIL(or_exprs.push_back(right_is_null_expr))) { + LOG_WARN("failed to push back expr", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_or_exprs(*expr_factory, + or_exprs, + or_expr))) { + LOG_WARN("failed to build or exprs", K(ret)); + } else if (OB_ISNULL(or_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(or_expr)); + } else if (OB_FAIL(or_expr->formalize(ctx->session_info_))) { + LOG_WARN("failed to formalize expr", K(ret)); + } else if (OB_FAIL(or_expr->pull_relation_id())) { + LOG_WARN("failed to pull releation id", K(ret)); + } else { + op_expr = or_expr; + } + } else { + op_expr = cmp_expr; + } + + if (OB_SUCC(ret) && OB_FAIL(right_stmt->get_condition_exprs().push_back(op_expr))) { + LOG_WARN("failed to push back op expr", K(ret)); + } + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(expr_factory->create_raw_expr(expr->has_flag(IS_WITH_ALL) + ? T_OP_NOT_EXISTS : T_OP_EXISTS, + exists_expr))) { + LOG_WARN("failed to create raw expr"); + } else if (OB_FAIL(OB_ISNULL(exists_expr))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(exists_expr)); + } else if (OB_FAIL(exists_expr->set_param_expr(right_hand))) { + LOG_WARN("failed to set param expr", K(ret)); + } else if (OB_FAIL(exists_expr->formalize(ctx->session_info_))) { + LOG_WARN("failed to formalize expr", K(ret)); + } else { + expr = exists_expr; + trans_happened = true; + } + return ret; +} + +int ObTransformUtils::prepare_trans_any_all_as_exists(ObTransformerCtx *ctx, + ObQueryRefRawExpr* right_hand, + ObSelectStmt *&trans_stmt) +{ + int ret = OB_SUCCESS; + trans_stmt = NULL; + if (OB_ISNULL(right_hand) || OB_ISNULL(ctx) || + OB_ISNULL(trans_stmt = right_hand->get_ref_stmt())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to prepare trans any all as exists", K(ret)); + } else if (trans_stmt->is_spj()) { + } else if (OB_FAIL(ObTransformUtils::create_stmt_with_generated_table(ctx, + trans_stmt, + trans_stmt))) { + LOG_WARN("failed to create stmt with generated table", K(ret)); + } else { + right_hand->set_ref_stmt(trans_stmt); + } + return ret; +} + +int ObTransformUtils::query_cmp_to_exists_value_cmp(ObItemType type, + bool is_with_all, + ObItemType& new_type) +{ + int64_t ret = OB_SUCCESS; + if (is_with_all) { + type = get_opposite_sq_cmp_type(type); + } + ret = ObTransformUtils::query_cmp_to_value_cmp(type, new_type); + return ret; +} + +ObItemType ObTransformUtils::get_opposite_sq_cmp_type(ObItemType item_type) +{ + ObItemType new_item_type = T_INVALID; + switch (item_type) { + case T_OP_SQ_EQ: + new_item_type = T_OP_SQ_NE; + break; + case T_OP_SQ_NE: + new_item_type = T_OP_SQ_EQ; + break; + case T_OP_SQ_GE: + new_item_type = T_OP_SQ_LT; + break; + case T_OP_SQ_GT: + new_item_type = T_OP_SQ_LE; + break; + case T_OP_SQ_LE: + new_item_type = T_OP_SQ_GT; + break; + case T_OP_SQ_LT: + new_item_type = T_OP_SQ_GE; + break; + default: + new_item_type = T_INVALID; + break; + } + return new_item_type; +} + +int ObTransformUtils::check_enable_global_parallel_execution(ObDMLStmt *stmt, + ObSQLSessionInfo *session, + ObQueryCtx *query_ctx, + bool &enable_parallel) +{ + int ret = OB_SUCCESS; + bool has_cursor_expr = false; + enable_parallel = false; + bool session_enable_auto_dop = false; + uint64_t session_query_dop = ObGlobalHint::UNSET_PARALLEL; + uint64_t session_dml_dop = ObGlobalHint::UNSET_PARALLEL; + if (OB_ISNULL(query_ctx) || OB_ISNULL(stmt) || OB_ISNULL(session)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(stmt->check_has_cursor_expression(has_cursor_expr))) { + LOG_WARN("fail to check cursor expression info", K(ret)); + } else if (query_ctx->has_pl_udf_ || has_cursor_expr || query_ctx->has_dblink_) { + enable_parallel = false; + } else if (query_ctx->get_global_hint().get_parallel_degree() > ObGlobalHint::DEFAULT_PARALLEL) { + enable_parallel = true; + } else if (OB_FAIL(session->get_force_parallel_dml_dop(session_dml_dop))) { + LOG_WARN("failed to get sys variable for force parallel query dop", K(ret)); + } else if (OB_FAIL(session->get_force_parallel_query_dop(session_query_dop))) { + LOG_WARN("failed to get sys variable for force parallel query dop", K(ret)); + } else if (ObGlobalHint::DEFAULT_PARALLEL < session_dml_dop || + ObGlobalHint::DEFAULT_PARALLEL < session_query_dop) { + enable_parallel = true; + } + return ret; +} + } // namespace sql } // namespace oceanbase diff --git a/src/sql/rewrite/ob_transform_utils.h b/src/sql/rewrite/ob_transform_utils.h index fb4426d8a9..98f5ce7ffc 100644 --- a/src/sql/rewrite/ob_transform_utils.h +++ b/src/sql/rewrite/ob_transform_utils.h @@ -1997,6 +1997,28 @@ public: const ObIArray &raw_having_exprs, const ObIArray &group_clause_exprs, ObIArray &having_exprs_for_deduce); + static int check_expr_used_as_condition(ObDMLStmt *stmt, + ObRawExpr *root_expr, + ObRawExpr *expr, + bool &used_as_condition); + static int inner_check_expr_used_as_condition(ObRawExpr *cur_expr, + ObRawExpr *expr, + bool parent_as_condition, + bool &used_as_condition); + static int check_can_trans_any_all_as_exists(ObTransformerCtx *ctx, + ObRawExpr* expr, + bool used_as_condition, + bool need_match_index, + bool& is_valid); + static int do_trans_any_all_as_exists(ObTransformerCtx *ctx, + ObRawExpr *&expr, + ObNotNullContext *not_null_ctx, + bool &trans_happened); + static ObItemType get_opposite_sq_cmp_type(ObItemType item_type); + static int check_enable_global_parallel_execution(ObDMLStmt *stmt, + ObSQLSessionInfo *session, + ObQueryCtx *query_ctx, + bool &enable_parallel); private: static int inner_get_lazy_left_join(ObDMLStmt *stmt, TableItem *table, @@ -2070,6 +2092,16 @@ private: ObRawExpr* match_expr, bool &need_calc, ObIArray &constraints); + static int check_stmt_can_trans_as_exists(ObSelectStmt *stmt, + ObTransformerCtx *ctx, + bool is_correlated, + bool need_match_index, + bool &match_index, + bool &is_valid); + static int prepare_trans_any_all_as_exists(ObTransformerCtx *ctx, + ObQueryRefRawExpr* right_hand, + ObSelectStmt *&trans_stmt); + static int query_cmp_to_exists_value_cmp(ObItemType type, bool is_with_all, ObItemType& new_type); }; class StmtUniqueKeyProvider