/** * 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_REWRITE #include "sql/rewrite/ob_transform_simplify_subquery.h" #include "sql/optimizer/ob_optimizer_util.h" #include "sql/rewrite/ob_transform_utils.h" #include "common/ob_smart_call.h" using namespace oceanbase::sql; int ObTransformSimplifySubquery::transform_one_stmt(common::ObIArray &parent_stmts, ObDMLStmt *&stmt, bool &trans_happened) { int ret = OB_SUCCESS; bool is_happened = false; UNUSED(parent_stmts); if (OB_FAIL(push_down_outer_join_condition(stmt, is_happened))) { LOG_WARN("failed to push down outer join condition", K(is_happened)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to push down outer join condition", K(is_happened)); } if (OB_SUCC(ret)) { if (OB_FAIL(transform_subquery_as_expr(stmt, is_happened))) { LOG_WARN("failed to transform subquery to expr", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform subquery to expr", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(remove_redundant_select(stmt, is_happened))) { LOG_WARN("failed to remove simple select", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to remove simple select", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_not_expr(stmt, is_happened))) { LOG_WARN("failed to transform not expr", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform not expr", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(add_limit_for_exists_subquery(stmt, is_happened))) { LOG_WARN("failed to add limit for exists subquery", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to add limit for exists subquery", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_any_all(stmt, is_happened))) { LOG_WARN("failed to transform_any_all", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform_any_all", K(is_happened)); } } if (OB_SUCC(ret)) { if (OB_FAIL(transform_exists_query(stmt, is_happened))) { LOG_WARN("failed to transform_exists_query", K(ret)); } else { trans_happened |= is_happened; LOG_TRACE("succeed to transform_exists_query", K(is_happened)); } } if (OB_SUCC(ret) && trans_happened) { if (OB_FAIL(add_transform_hint(*stmt))) { LOG_WARN("failed to add transform hint", K(ret)); } } return ret; } int ObTransformSimplifySubquery::transform_subquery_as_expr(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; bool is_happened = false; ObSEArray relation_expr_pointers; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret), K(stmt)); } else if (OB_FAIL(stmt->get_relation_exprs(relation_expr_pointers))) { LOG_WARN("failed to get_relation_exprs", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < relation_expr_pointers.count(); ++i) { ObRawExpr *expr = NULL; if (OB_FAIL(relation_expr_pointers.at(i).get(expr))) { LOG_WARN("failed to get relation expr", K(ret)); } else if (OB_FAIL(try_trans_subquery_in_expr(stmt, expr, is_happened))) { LOG_WARN("failed to transform expr", K(ret)); } else { trans_happened |= is_happened; } } return ret; } int ObTransformSimplifySubquery::try_trans_subquery_in_expr(ObDMLStmt *stmt, ObRawExpr *&expr, bool &trans_happened) { int ret = OB_SUCCESS; bool is_happened = false; trans_happened = false; bool is_stack_overflow = false; if (OB_ISNULL(stmt) || OB_ISNULL(expr) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("parameters have null", K(stmt), K(expr), K(ctx_)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("failed to check stack overflow", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); } else if (IS_SUBQUERY_COMPARISON_OP(expr->get_expr_type()) || T_OP_EXISTS == expr->get_expr_type() || T_OP_NOT_EXISTS == expr->get_expr_type()) { // 如果 expr 的param 必须是 subquery,那么不去改写它包含的子查询 //do nothing } else if (expr->is_query_ref_expr()) { //如果是 query ref expr,那么尝试改写 if (OB_FAIL(do_trans_subquery_as_expr(stmt, expr, is_happened))) { LOG_WARN("failed to do_trans_subquery_as_expr", K(ret)); } else if (is_happened) { trans_happened = true; } } else if (expr->has_flag(CNT_SUB_QUERY)) { //如果是 non-terminal expr,那么继续遍历孩子节点 for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(try_trans_subquery_in_expr(stmt, expr->get_param_expr(i), is_happened)))) { LOG_WARN("failed to trans param expr", K(ret)); } else if (is_happened) { trans_happened = true; } } if (OB_SUCC(ret) && trans_happened) { if (OB_FAIL(expr->formalize(ctx_->session_info_))) { LOG_WARN("failed to formalize expr", K(ret)); } } } return ret; } int ObTransformSimplifySubquery::do_trans_subquery_as_expr(ObDMLStmt *stmt, ObRawExpr *&expr, bool &trans_happened) { int ret = OB_SUCCESS; bool is_valid = false; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("parameters have null", K(ret), K(stmt), K(expr)); } else if (expr->is_query_ref_expr()) { ObQueryRefRawExpr *query_ref = static_cast(expr); ObSelectStmt *sub_stmt = query_ref->get_ref_stmt(); ObRawExpr *sub_expr = NULL; if (sub_stmt->get_stmt_hint().has_disable_hint(T_UNNEST) || sub_stmt->get_stmt_hint().enable_no_rewrite()) { // do nothing } else if (query_ref->is_cursor()) { /*do nothing*/ } else if (OB_FAIL(is_subquery_to_expr_valid(sub_stmt, is_valid))) { LOG_WARN("fail to check subquery", K(ret)); } else if (!is_valid) { // do nothing } else if (OB_UNLIKELY(1 != sub_stmt->get_select_item_size()) || OB_ISNULL(sub_expr = sub_stmt->get_select_item(0).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sub stmt has invalid select item", K(ret), K(sub_stmt->get_select_item_size()), K(sub_expr)); } else if (sub_expr->has_flag(CNT_ROWNUM)) {// 当 select expr 包含 rownum 时不能进行转换 is_valid = false; } else { if (OB_FAIL(ObTransformUtils::decorrelate(sub_expr, stmt->get_current_level()))) { LOG_WARN("failed to decorrleation expr", K(ret)); } else if (OB_FAIL(sub_stmt->pullup_stmt_level())) { LOG_WARN("failed to pullup stmt level", K(ret)); } else if (OB_FAIL(sub_stmt->adjust_view_parent_namespace_stmt( stmt->get_parent_namespace_stmt()))) { LOG_WARN("failed to adjust view parent namespace stmt", K(ret)); } else if (OB_FAIL(sub_stmt->adjust_subquery_stmt_parent(sub_stmt, stmt))) { LOG_WARN("failed to adjust subquery parent stmt", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::remove_item( stmt->get_subquery_exprs(), query_ref))) { LOG_WARN("failed to remove child stmt", K(ret)); } else if (OB_FAIL(append(stmt->get_subquery_exprs(), sub_stmt->get_subquery_exprs()))) { LOG_WARN("failed to append stmt subquery", K(ret)); } else if (OB_FAIL(sub_expr->formalize(ctx_->session_info_))) { LOG_WARN("failed to formalize expr", K(ret)); } else { ObSEArray old_expr; ObSEArray new_expr; if (OB_FAIL(old_expr.push_back(expr)) || OB_FAIL(new_expr.push_back(sub_expr))) { LOG_WARN("push expr into array failed", K(ret)); } else if (OB_FAIL(stmt->replace_inner_stmt_expr(old_expr, new_expr))) { LOG_WARN("stmt replace inner expr failed", K(ret)); } else { trans_happened = true; } } } } return ret; } int ObTransformSimplifySubquery::is_subquery_to_expr_valid(const ObSelectStmt *stmt, bool &is_valid) { int ret = OB_SUCCESS; is_valid = false; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret), K(stmt)); } else if (0 == stmt->get_from_item_size() && 1 == stmt->get_select_item_size() && !stmt->is_contains_assignment() // && !stmt->has_subquery() && 0 == stmt->get_aggr_item_size() && 0 == stmt->get_window_func_count() && 0 == stmt->get_condition_size() && 0 == stmt->get_having_expr_size() && !stmt->has_limit() && !stmt->is_hierarchical_query() && !stmt->is_set_stmt()) { is_valid = true; } return ret; } /** * @brief * transform not col op subquery to col !op subquery, eg: * not c1 not in --> c1 = any * not c1 in --> c1 != all * not c1 op any --> c1 !op all, where op \in {<, >, <=, >=} * not c1 op all --> c1 !op any, where op \in {<, >, <=, >=} * not c1 = any --> c1 != all * not c1 != all --> c1 = any * @param stmt * @param trans_happened * @return int */ int ObTransformSimplifySubquery::transform_not_expr(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; ObRawExprFactory *expr_factory = NULL; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(ctx_)); } else if (OB_ISNULL(expr_factory = ctx_->expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ctx_ info", K(expr_factory)); } else { ObSEArray old_exprs; ObSEArray new_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_condition_size(); ++i) { ObRawExpr *expr = stmt->get_condition_expr(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret)); } else if (expr->get_expr_type() == T_OP_NOT && expr->has_flag(CNT_SUB_QUERY)) { ObRawExpr *param = expr->get_param_expr(0); ObItemType expr_type = param->get_expr_type(); if (OB_ISNULL(param)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(*param)); } else if (expr_type == T_OP_SQ_NSEQ) { // same to T_OP_SQ_EQ as long as the expr is not null // do nothing current now } else if (param->has_flag(IS_WITH_ALL) || param->has_flag(IS_WITH_ANY)) { ObRawExpr *new_param = NULL; 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); // 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 bool is_not_valid = (expr_type == T_OP_SQ_EQ && param->has_flag(IS_WITH_ALL)) || (expr_type == T_OP_SQ_NE && param->has_flag(IS_WITH_ANY)) || (new_type == T_INVALID); if (is_not_valid) { } else if (OB_FAIL(expr_factory->create_raw_expr( ObRawExpr::EXPR_OPERATOR, new_type, new_param))) { LOG_WARN("failed to create raw expr", K(ret)); } else if (OB_FALSE_IT(new_op_expr = static_cast(new_param))) { } else if (OB_FALSE_IT(new_op_expr->set_subquery_key(key_flag))) { } else if (OB_FAIL(append(new_op_expr->get_param_exprs(), static_cast(param)->get_param_exprs()))) { LOG_WARN("failed to append param exprs", K(ret)); } else if (OB_FALSE_IT(new_param = new_op_expr)) { } else if (OB_FAIL(new_exprs.push_back(new_param))) { LOG_WARN("failed to push back new expr", K(ret)); } else if (OB_FAIL(old_exprs.push_back(expr))) { LOG_WARN("failed to push back old expr", K(ret)); } } } } if (OB_FAIL(ret) || old_exprs.empty() || new_exprs.empty()) { } else if (OB_FAIL(stmt->replace_inner_stmt_expr(old_exprs, new_exprs))) { LOG_WARN("failed to replace expr in stmt", K(ret)); } else { trans_happened = true; } } 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) { int ret = OB_SUCCESS; trans_happened = false; ObSelectStmt *new_stmt = NULL; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret)); } else if (stmt->is_select_stmt()) { ObSelectStmt *sel_stmt = static_cast(stmt); if (OB_FAIL(try_remove_redundant_select(*sel_stmt, new_stmt))) { LOG_WARN("failed to check can remove simple select", K(ret)); } else if (NULL != new_stmt) { stmt = new_stmt; trans_happened = true; } } return ret; } int ObTransformSimplifySubquery::try_remove_redundant_select(ObSelectStmt &stmt, ObSelectStmt *&new_stmt) { int ret = OB_SUCCESS; new_stmt = NULL; ObRawExpr *sel_expr = NULL; ObQueryRefRawExpr *query_expr = NULL; ObSelectStmt *subquery = NULL; bool is_valid = false; if (!stmt.is_set_stmt() && !stmt.is_hierarchical_query() && 1 == stmt.get_select_item_size() && 0 == stmt.get_from_item_size() && 0 == stmt.get_condition_size() && 0 == stmt.get_aggr_item_size() && 0 == stmt.get_having_expr_size() && 0 == stmt.get_window_func_count() && !stmt.has_limit()) { if (OB_ISNULL(sel_expr = stmt.get_select_item(0).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null expr", K(ret)); } else if (!sel_expr->is_query_ref_expr()) { // do nothing } else if (FALSE_IT(query_expr = static_cast(sel_expr))) { // never reach } else if (OB_ISNULL(subquery = query_expr->get_ref_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null stmt", K(ret)); } else if (OB_FAIL(check_subquery_valid(*subquery, is_valid))) { LOG_WARN("failed to check subquery valid", K(ret)); } else if (!is_valid) { // do nothing } else if (OB_FAIL(subquery->pullup_stmt_level())) { LOG_WARN("failed to pullup stmt level", K(ret)); } else if (OB_FAIL(subquery->adjust_view_parent_namespace_stmt( stmt.get_parent_namespace_stmt()))) { LOG_WARN("failed to adjust view parent namespace stmt", K(ret)); } else { new_stmt = subquery; } } return ret; } /** * @brief check_subquery_valid * check subquery return equal one row, if empty do nothing * has limit 可能使结果为空不做改写; * select ... where rownum >2; rownum不包含1必空,包含判断较难,暂不处理 * subquery should in format of: * 1. select ... from dual; no where condition * 2. select aggr() ...; <- no group by, no having */ int ObTransformSimplifySubquery::check_subquery_valid(ObSelectStmt &stmt, bool &is_valid) { int ret = OB_SUCCESS; is_valid = false; ObRawExpr *sel_expr = NULL; if (stmt.is_set_stmt() || stmt.is_hierarchical_query()) { // do nothing } else { if (OB_UNLIKELY(1 != stmt.get_select_item_size()) || OB_ISNULL(sel_expr = stmt.get_select_item(0).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected subquery", K(ret), K(stmt.get_select_item_size()), K(sel_expr)); } else if (OB_NOT_NULL(stmt.get_limit_expr())) { // do nothing } else if (0 == stmt.get_from_item_size() && 0 == stmt.get_condition_size()) { is_valid = true; } else if (0 == stmt.get_group_expr_size() && 0 == stmt.get_rollup_expr_size() && 0 == stmt.get_having_expr_size() && sel_expr->has_flag(CNT_AGG)) { is_valid = true; } } return ret; } //对于left join, 将仅含 right table column 且包含 subquery 的 on condition 下压到 right table int ObTransformSimplifySubquery::push_down_outer_join_condition(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is NULL", K(ret), K(stmt)); } else if (OB_FAIL(ObTransformUtils::right_join_to_left(stmt))) { LOG_WARN("failed to change right join to left", K(ret)); } else { ObIArray &join_tables = stmt->get_joined_tables(); for (int64_t i = 0; OB_SUCC(ret) && i < join_tables.count(); ++i) { bool is_happened = false; if (OB_FAIL(push_down_outer_join_condition(stmt, join_tables.at(i), is_happened))) { LOG_WARN("failed to push down outer join condition", K(ret)); } else { trans_happened |= is_happened; } } } return ret; } int ObTransformSimplifySubquery::push_down_outer_join_condition(ObDMLStmt *stmt, TableItem *join_table, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; bool left_happend = false; bool right_happend = false; JoinedTable *cur_joined = NULL; if (OB_ISNULL(stmt) || OB_ISNULL(join_table)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(ret)); } else if (!join_table->is_joined_table()) { /*do nothing*/ } else if (FALSE_IT(cur_joined = static_cast(join_table))) { /*do nothing*/ } else if (OB_FAIL(SMART_CALL(push_down_outer_join_condition(stmt, cur_joined->left_table_, left_happend)))) { LOG_WARN("failed to push down outer join condition", K(ret)); } else if (OB_FAIL(SMART_CALL(push_down_outer_join_condition(stmt, cur_joined->right_table_, right_happend)))) { LOG_WARN("failed to push down outer join condition", K(ret)); } else if (OB_FAIL(try_push_down_outer_join_conds(stmt, cur_joined, trans_happened))) { LOG_WARN("fail to get outer join push down conditions", K(ret)); } else { trans_happened |= left_happend || right_happend; } return ret; } //当 left join 右表为 basic/generate/join table 时, 对 on condition 中包含 subquery //且仅包含本层右表列的条件进行下压: // 1. 由右表生成generate table; // 2. 下压满足条件 on condition. int ObTransformSimplifySubquery::try_push_down_outer_join_conds(ObDMLStmt *stmt, JoinedTable *join_table, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; ObSqlBitSet<> right_table_ids; if (OB_ISNULL(stmt) || OB_ISNULL(join_table) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(ret)); } else if (!join_table->is_left_join()) { /*do nothing*/ } else if (OB_ISNULL(join_table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(ret)); } else if (!join_table->right_table_->is_basic_table() && !join_table->right_table_->is_generated_table() && !join_table->right_table_->is_temp_table() && !join_table->right_table_->is_joined_table()) { /*do nothing*/ } else if (OB_FAIL(stmt->get_table_rel_ids(*join_table->right_table_, right_table_ids))) { LOG_WARN("failed to get target table rel ids", K(ret)); } else { ObSEArray push_down_conds; ObIArray &join_conds = join_table->get_join_conditions(); for (int64_t i = 0; OB_SUCC(ret) && i < join_conds.count(); ++i) { if (OB_ISNULL(join_conds.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(ret)); } else if (join_conds.at(i)->get_relation_ids().is_subset(right_table_ids) && join_conds.at(i)->has_flag(CNT_SUB_QUERY)) { if (OB_FAIL(push_down_conds.push_back(join_conds.at(i)))) { LOG_WARN("failed to push back expr", K(ret)); } } } TableItem *view_item = NULL; if (OB_FAIL(ret) || push_down_conds.empty()) { /*do nothing*/ } else if (OB_FAIL(ObTransformUtils::create_view_with_table(stmt, ctx_, join_table->right_table_, view_item))) { LOG_WARN("failed to create view with table", K(ret)); } else if (OB_FAIL(push_down_on_condition(stmt, join_table, push_down_conds))) { LOG_WARN("failed to push down on condition", K(ret)); } else { trans_happened = true; } } return ret; } //将left join 部分连接条件conds 下推到 right generate table //right table 为仅含 select 输出的 generate table int ObTransformSimplifySubquery::push_down_on_condition(ObDMLStmt *stmt, JoinedTable *join_table, ObIArray &conds) { int ret = OB_SUCCESS; ObSEArray new_conds; ObSelectStmt *child_stmt = NULL; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(join_table) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->allocator_) || OB_ISNULL(join_table->right_table_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULL", K(ret)); } else if (!join_table->is_left_join() || !join_table->right_table_->is_generated_table() || OB_ISNULL(child_stmt = join_table->right_table_->ref_query_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected join table", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::remove_item(join_table->get_join_conditions(), conds))) { LOG_WARN("failed to remove item", K(ret)); } else if (OB_FAIL(ObTransformUtils::move_expr_into_view(*ctx_->expr_factory_, *stmt, *join_table->right_table_, conds, new_conds))) { LOG_WARN("failed to move expr into view", K(ret)); } else if (OB_FAIL(child_stmt->add_condition_exprs(new_conds))) { LOG_WARN("failed to add new conditions exprs", K(ret)); } else if (OB_FAIL(stmt->formalize_stmt(ctx_->session_info_))) { LOG_WARN("failed to formalize stmt", K(ret)); } return ret; } int ObTransformSimplifySubquery::add_limit_for_exists_subquery(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; bool happened = false; trans_happened = false; ObSEArray relation_exprs; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ptr", K(ret), K(stmt)); } else if (OB_FAIL(stmt->get_relation_exprs(relation_exprs))) { LOG_WARN("failed to relation exprs", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < relation_exprs.count(); i++) { ObRawExpr *expr = relation_exprs.at(i); if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ptr", K(ret)); } else if (OB_FAIL(recursive_add_limit_for_exists_expr(expr, happened))) { LOG_WARN("failed recursive add limit for exists expr", K(ret), K(expr)); } else { trans_happened |= happened; } } } return ret; } int ObTransformSimplifySubquery::recursive_add_limit_for_exists_expr(ObRawExpr *expr, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; bool happened = false; bool is_stack_overflow = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ptr", K(ret), K(expr)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(is_stack_overflow), K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(is_stack_overflow), K(ret)); } else if (expr->has_flag(CNT_SUB_QUERY)) { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { ObRawExpr *param_expr = expr->get_param_expr(i); if (OB_ISNULL(param_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ptr", K(ret), K(param_expr)); } else if (OB_FAIL(SMART_CALL(recursive_add_limit_for_exists_expr(param_expr, happened)))) { LOG_WARN("failed recursive add limit for exists expr", K(ret), K(param_expr)); } else { trans_happened |= happened; } } if (OB_SUCC(ret) && (T_OP_EXISTS == expr->get_expr_type() || T_OP_NOT_EXISTS == expr->get_expr_type())) { if (expr->get_param_count() != 1 || OB_ISNULL(expr->get_param_expr(0)) || !expr->get_param_expr(0)->is_query_ref_expr()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected expr type", KPC(expr)); } else { ObSelectStmt *subquery = NULL; ObOpRawExpr *op = static_cast(expr); ObQueryRefRawExpr *subq_expr = static_cast(op->get_param_expr(0)); if (OB_ISNULL(subq_expr) || OB_ISNULL(subquery = subq_expr->get_ref_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null ptr", K(ret), K(subq_expr), K(subquery)); } else if (!subquery->has_limit() && !subquery->is_contains_assignment()) { if (OB_FAIL(ObTransformUtils::set_limit_expr(subquery, ctx_))) { LOG_WARN("add limit expr failed", K(*subquery), K(ret)); } else { trans_happened = true; } } else { /*do nothing*/ } } } } return ret; } int ObTransformSimplifySubquery::transform_any_all(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; bool is_happened = false; ObSEArray relation_expr_pointers; if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt is NULL", K(ret)); } else if (!stmt->is_sel_del_upd()) { // do nothing } else if (OB_FAIL(stmt->get_relation_exprs(relation_expr_pointers))) { LOG_WARN("failed to get_relation_exprs", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < relation_expr_pointers.count(); ++i) { ObRawExpr *target = NULL; if (OB_FAIL(relation_expr_pointers.at(i).get(target))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("find to get expr from group", K(ret), K(target)); } else if (OB_FAIL(try_transform_any_all(stmt, target, is_happened))) { LOG_WARN("fail to transform expr", K(ret)); } else if (!is_happened) { // do nothing } else if (OB_FAIL(relation_expr_pointers.at(i).set(target))) { LOG_WARN("failed to set expr", K(ret)); } else { trans_happened = true; } } // for end return ret; } int ObTransformSimplifySubquery::try_transform_any_all(ObDMLStmt *stmt, ObRawExpr *&expr, bool &trans_happened) { int ret = OB_SUCCESS; bool is_happened = false; bool is_stack_overflow = false; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have null", K(ret), K(stmt), K(expr)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("failed to check stack overflow", K(ret)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); } else if (IS_SUBQUERY_COMPARISON_OP(expr->get_expr_type())) { if (OB_FAIL(do_transform_any_all(stmt, expr, is_happened))) { LOG_WARN("failed to do_trans_any_all", K(ret)); } else { trans_happened |= is_happened; } } else if (expr->has_flag(CNT_SUB_QUERY)) { //check children for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(try_transform_any_all(stmt, expr->get_param_expr(i), is_happened)))) { LOG_WARN("failed to try_transform_any_all for param", K(ret)); } else { trans_happened |= is_happened; } } } return ret; } int ObTransformSimplifySubquery::do_transform_any_all(ObDMLStmt *stmt, ObRawExpr *&expr, bool &trans_happened) { int ret = OB_SUCCESS; bool is_happened = false; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { 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(transform_any_all_as_min_max(stmt, expr, is_happened))) { LOG_WARN("failed to trans_any_all_as_min_max", K(ret)); } else { trans_happened |= is_happened; } if (OB_FAIL(ret)) { } else if (OB_FAIL(eliminate_any_all_before_subquery(stmt, expr, is_happened))) { LOG_WARN("failed to eliminate_any_all_before_scalar_query", K(ret)); } else { trans_happened |= is_happened; } } return ret; } int ObTransformSimplifySubquery::check_any_all_as_min_max(ObRawExpr *expr, bool &is_valid) { int ret = OB_SUCCESS; ObSelectStmt *child_stmt = NULL; is_valid = false; //check op_expr if (OB_ISNULL(expr) || OB_ISNULL(ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have null", K(ret), K(expr)); } else if (IS_SUBQUERY_COMPARISON_OP(expr->get_expr_type()) && T_OP_SQ_EQ != expr->get_expr_type() && T_OP_SQ_NSEQ != expr->get_expr_type() && T_OP_SQ_NE != expr->get_expr_type()) { if (OB_ISNULL(expr->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param expr is null", K(ret)); } else if (expr->get_param_expr(1)->is_query_ref_expr()) { child_stmt = static_cast( expr->get_param_expr(1))->get_ref_stmt(); if (OB_ISNULL(child_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child stmt is null", K(ret)); } } } //check child_stmt if (OB_FAIL(ret) || OB_ISNULL(child_stmt)) { } else if (!child_stmt->has_group_by() && !child_stmt->has_having() && !child_stmt->is_set_stmt() && !child_stmt->has_limit() && !child_stmt->is_hierarchical_query() && 1 == child_stmt->get_select_item_size() && 1 == child_stmt->get_table_size()) { ObRawExpr *sel_expr = child_stmt->get_select_item(0).expr_; if (OB_ISNULL(sel_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select expr is NULL", K(ret)); } else if (sel_expr->is_column_ref_expr()) { ObColumnRefRawExpr *col_expr = static_cast(sel_expr); bool is_nullable = true; bool is_match = false; ObArenaAllocator alloc; EqualSets &equal_sets = ctx_->equal_sets_; ObSEArray const_exprs; if (col_expr->get_expr_level() != child_stmt->get_current_level()) { /*外层stmt的列,不改写*/ } else if (OB_FAIL(child_stmt->get_stmt_equal_sets(equal_sets, alloc, true, EQUAL_SET_SCOPE::SCOPE_WHERE))) { LOG_WARN("failed to get stmt equal sets", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(child_stmt->get_condition_exprs(), const_exprs))) { LOG_WARN("failed to compute const equivalent exprs", K(ret)); } else if (OB_FAIL(ObTransformUtils::is_match_index(ctx_->sql_schema_guard_, child_stmt, col_expr, is_match, &equal_sets, &const_exprs))) { LOG_WARN("failed to check is match index prefix", K(ret)); } else if (!is_match) { /*不能利用基表索引,不改写*/ } else if (expr->has_flag(IS_WITH_ANY)) { is_valid = true; } else if (expr->has_flag(IS_WITH_ALL)) { if (OB_FAIL(ObTransformUtils::is_column_nullable(child_stmt, ctx_->schema_checker_, col_expr, ctx_->session_info_, is_nullable))) { LOG_WARN("failed to check is column nullable", K(ret)); } else if (!is_nullable) { is_valid = true; } } equal_sets.reuse(); } } return ret; } int ObTransformSimplifySubquery::transform_any_all_as_min_max(ObDMLStmt *stmt, ObRawExpr *expr, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; bool is_valid = false; if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have null", K(ret), K(stmt), K(expr)); } else if (OB_FAIL(check_any_all_as_min_max(expr, is_valid))) { LOG_WARN("failed to check_any_all_as_min_max", K(ret)); } else if (!is_valid) { /* do nothing */ } else if (OB_ISNULL(expr->get_param_expr(1)) || OB_UNLIKELY(!expr->get_param_expr(1)->is_query_ref_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr has invalid param", K(ret), K(expr->get_param_expr(1))); } else { ObQueryRefRawExpr *query_ref = static_cast(expr->get_param_expr(1)); ObSelectStmt *child_stmt = query_ref->get_ref_stmt(); ObItemType aggr_type = get_aggr_type(expr->get_expr_type(), expr->has_flag(IS_WITH_ALL)); if (OB_FAIL(do_transform_any_all_as_min_max(child_stmt, aggr_type, expr->has_flag(IS_WITH_ALL), trans_happened))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to do_trans_any_all_as_min_max", K(ret)); } } return ret; } ObItemType ObTransformSimplifySubquery::get_aggr_type(ObItemType op_type, bool is_with_all) { ObItemType aggr_type = T_INVALID; if (T_OP_SQ_LE == op_type || T_OP_SQ_LT == op_type) { if (is_with_all) { aggr_type = T_FUN_MIN; } else { /*with_any*/ aggr_type = T_FUN_MAX; } } else if (T_OP_SQ_GE == op_type || T_OP_SQ_GT == op_type) { if (is_with_all) { aggr_type = T_FUN_MAX; } else { /*with_all*/ aggr_type = T_FUN_MIN; } } return aggr_type; } int ObTransformSimplifySubquery::do_transform_any_all_as_min_max(ObSelectStmt *stmt, const ObItemType aggr_type, bool is_with_all, bool &trans_happened) { int ret = OB_SUCCESS; ObRawExpr *col_expr = NULL; ObAggFunRawExpr *aggr_expr = NULL; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params or data member is NULL", K(ret), K(stmt), K(ctx_)); } else if (stmt->get_select_item_size() <= 0 || OB_ISNULL(col_expr = stmt->get_select_item(0).expr_) || (T_FUN_MAX != aggr_type && T_FUN_MIN != aggr_type)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("params have incorrect value", K(ret), K(stmt->get_select_items()), K(col_expr), K(aggr_type)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(aggr_type, aggr_expr))) { LOG_WARN("fail to create raw expr", K(ret), K(aggr_expr)); } else if (OB_ISNULL(aggr_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to create aggr expr", K(ret), K(aggr_type)); } else if (OB_FAIL(aggr_expr->add_real_param_expr(col_expr))) { LOG_WARN("fail to add param expr", K(ret)); } else if (FALSE_IT(aggr_expr->set_expr_level(stmt->get_current_level()))) { } else if (OB_FAIL(aggr_expr->formalize(ctx_->session_info_))) { LOG_WARN("failed to formalize expr", K(ret)); } else if (OB_FAIL(aggr_expr->pull_relation_id_and_levels(stmt->get_current_level()))) { LOG_WARN("failed to pull relation id", K(ret)); } else { stmt->get_select_item(0).expr_ = aggr_expr; if (OB_FAIL(stmt->add_agg_item(*aggr_expr))) { LOG_WARN("fail to add agg_item", K(ret)); } else if (is_with_all) { ObOpRawExpr *is_not_expr = NULL; if (OB_FAIL(ObTransformUtils::add_is_not_null(ctx_, stmt, aggr_expr, is_not_expr))) { LOG_WARN("failed to add is not null", K(ret)); } else if (OB_FAIL(stmt->add_having_expr(is_not_expr))) { LOG_WARN("failed to add having expr", K(ret)); } } if (OB_SUCC(ret)) { trans_happened = true; } } return ret; } int ObTransformSimplifySubquery::eliminate_any_all_before_subquery(ObDMLStmt *stmt, ObRawExpr *&expr, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; bool can_be_removed = false; if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("parameters have null", K(ret), K(stmt), K(expr)); } else if (OB_FAIL(check_any_all_removeable(expr, can_be_removed))) { LOG_WARN("failed to check is any all removeable", K(ret)); } else if (!can_be_removed) { /* do nothing */ } else if (OB_ISNULL(expr->get_param_expr(1)) || OB_UNLIKELY(!expr->get_param_expr(1)->is_query_ref_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr has invalid param", K(ret), K(expr->get_param_expr(1))); } else { ObQueryRefRawExpr *query_ref = static_cast(expr->get_param_expr(1)); if (OB_FAIL(clear_any_all_flag(stmt, expr, query_ref))) { LOG_WARN("failed to clear any all flag", K(ret)); } else { trans_happened = true; } } return ret; } int ObTransformSimplifySubquery::check_any_all_removeable(ObRawExpr *expr, bool &can_be_removed) { int ret = OB_SUCCESS; ObSelectStmt *sub_stmt = NULL; bool is_expr_query = false; bool is_aggr_query = false; can_be_removed = false; //check op if (IS_SUBQUERY_COMPARISON_OP(expr->get_expr_type())) { if (OB_ISNULL(expr->get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param expr is null", K(ret)); } else if (expr->get_param_expr(1)->is_query_ref_expr()) { ObQueryRefRawExpr *query_ref = static_cast(expr->get_param_expr(1)); if (OB_ISNULL(sub_stmt = query_ref->get_ref_stmt())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sub_stmt is null", K(ret)); } } } //check sub_stmt if (OB_FAIL(ret) || OB_ISNULL(sub_stmt)) { } else if (OB_FAIL(ObTransformUtils::is_expr_query(sub_stmt, is_expr_query))) { LOG_WARN("failed to check sub stmt is expr query", K(ret)); } else if (is_expr_query) { can_be_removed = true; } else if (OB_FAIL(ObTransformUtils::is_aggr_query(sub_stmt, is_aggr_query))) { LOG_WARN("failed to check sub stmt is aggr query", K(ret)); } else if (is_aggr_query) { can_be_removed = true; } return ret; } int ObTransformSimplifySubquery::clear_any_all_flag(ObDMLStmt *stmt, ObRawExpr *&expr, ObQueryRefRawExpr *query_ref) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt) || OB_ISNULL(expr) || OB_ISNULL(query_ref) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("parameters have null", K(ret), K(stmt), K(expr), K(query_ref), K(ctx_)); } else if (IS_SUBQUERY_COMPARISON_OP(expr->get_expr_type())) { query_ref->set_is_set(false); ObOpRawExpr *tmp_op = NULL; ObItemType op_type = query_cmp_to_value_cmp(expr->get_expr_type()); if (T_INVALID == op_type) { ret = OB_ERR_UNEXPECTED; LOG_WARN("op type is not correct", K(ret), K(op_type)); } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(op_type, tmp_op))) { LOG_WARN("failed to create tmp op", K(ret)); } else if (OB_ISNULL(tmp_op)) { ret = OB_ERR_UNEXPECTED; } else if (OB_FAIL(tmp_op->set_param_exprs(expr->get_param_expr(0), expr->get_param_expr(1)))) { LOG_WARN("failed to set params", K(ret)); } else if (OB_FAIL(tmp_op->formalize(ctx_->session_info_))) { LOG_WARN("failed to formalize tmp op", K(ret)); } else if (OB_FAIL(tmp_op->pull_relation_id_and_levels( stmt->get_current_level()))) { LOG_WARN("failed to pull relation id", K(ret)); } else { expr = tmp_op; } } return ret; } ObItemType ObTransformSimplifySubquery::query_cmp_to_value_cmp(const ObItemType cmp_type) { ObItemType ret = T_INVALID; switch (cmp_type) { case T_OP_SQ_EQ: ret = T_OP_EQ; break; case T_OP_SQ_NSEQ: ret = T_OP_NSEQ; break; case T_OP_SQ_LE: ret = T_OP_LE; break; case T_OP_SQ_LT: ret = T_OP_LT; break; case T_OP_SQ_GE: ret = T_OP_GE; break; case T_OP_SQ_GT: ret = T_OP_GT; break; case T_OP_SQ_NE: ret = T_OP_NE; break; default: ret = T_INVALID; break; } return ret; } int ObTransformSimplifySubquery::transform_exists_query(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; ObSEArray conditions; if (OB_ISNULL(stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is null", K(ret), K(stmt)); } else if (!stmt->has_subquery()) { //do nothing } else if (OB_FAIL(conditions.assign(stmt->get_condition_exprs()))) { LOG_WARN("failed to assign a new condition exprs", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < conditions.count(); ++i) { bool is_happened = false; if (OB_FAIL(transform_one_expr(stmt, conditions.at(i), is_happened))) { LOG_WARN("failed to transform one subquery expr", K(ret)); } else { trans_happened |= is_happened; } } } return ret; } int ObTransformSimplifySubquery::transform_one_expr(ObDMLStmt *stmt, ObRawExpr *expr, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; if (OB_ISNULL(stmt) || OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL pointer error", K(ret)); //bug:https://work.aone.alibaba-inc.com/issue/25356955 暂时禁掉含有rownum的condition } else if (expr->has_flag(CNT_ROWNUM)) { /*do nothing */ } else { bool can_be = false; bool need_add_limit_constraint = false; ObRawExpr *old_expr = expr; if (OB_FAIL(recursive_eliminate_subquery(stmt, expr, can_be, need_add_limit_constraint, trans_happened))) { LOG_WARN("failed to recursive eliminate subquery", KP(expr), K(ret)); } else if (can_be) { if (OB_FAIL(eliminate_subquery_in_exists(stmt, expr, need_add_limit_constraint, trans_happened))) { LOG_WARN("failed to eliminate subquery in exists", KP(expr), K(ret)); } else if (OB_FAIL(ObOptimizerUtil::remove_item(stmt->get_condition_exprs(), old_expr))) { LOG_WARN("failed to remove condition expr", K(ret)); } else if (OB_FAIL(stmt->add_condition_expr(expr))) { LOG_WARN("add new condition expr failed", KP(expr), K(ret)); } else { /*do nothing*/ } } } return ret; } int ObTransformSimplifySubquery::recursive_eliminate_subquery(ObDMLStmt *stmt, ObRawExpr *expr, bool &can_be_eliminated, bool &need_add_limit_constraint, bool &trans_happened) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("NULL pointer error", K(expr), K(ret)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("check stack overflow failed", K(ret), K(is_stack_overflow)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); } else if (expr->has_flag(CNT_SUB_QUERY)) { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { if (OB_FAIL(SMART_CALL(recursive_eliminate_subquery(stmt, expr->get_param_expr(i), can_be_eliminated, need_add_limit_constraint, trans_happened)))) { LOG_WARN("failed to recursive eliminate subquery", K(ret)); } else if (can_be_eliminated) { if (OB_FAIL(eliminate_subquery_in_exists(stmt, expr->get_param_expr(i), need_add_limit_constraint, trans_happened))) { LOG_WARN("failed to eliminate subquery in exists", K(ret), KP(expr)); } else { LOG_TRACE("succeed to eliminate subquery", K(i), K(can_be_eliminated), K(need_add_limit_constraint), K(ret)); can_be_eliminated = false; need_add_limit_constraint = false; } } } if (OB_SUCC(ret) && OB_FAIL(eliminate_subquery(stmt, expr, can_be_eliminated, need_add_limit_constraint, trans_happened))) { LOG_WARN("failed to eliminate subquery", K(ret)); } else { /*do nothing*/ } } else { /*do nothing*/ } LOG_TRACE("finish to eliminate subquery", K(can_be_eliminated), K(ret)); return ret; } //1. 如果是Exist/Not Exist // 1.1 判断是否可以消除subquery // 2.2 如果不能消除: // a. 消除select list --> select 1 // b. 消除group by // c. 消除order by //2. 如果是ANY/ALL // 2.1 消除group by // 2.2 非相关any子查询如果select item为const item,则添加limit 1, // eg: select * from t1 where c1 in (select 1 from t2); // ==> select * from t1 where c1 in (select 1 from t2 limit 1); // 2.3 消除distinct int ObTransformSimplifySubquery::eliminate_subquery(ObDMLStmt *stmt, ObRawExpr *expr, bool &can_be_eliminated, bool &need_add_limit_constraint, bool &trans_happened) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("expr is NULL in eliminate subquery", K(ret)); } else if (!expr->has_flag(CNT_SUB_QUERY)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("no subquery in expr", K(ret)); } else { ObQueryRefRawExpr *subq_expr = NULL; ObSelectStmt *subquery = NULL; const ObRawExpr *left_hand = NULL; bool check_status = false; if (T_OP_EXISTS == expr->get_expr_type() || T_OP_NOT_EXISTS == expr->get_expr_type()) { if (OB_ISNULL(subq_expr = static_cast(expr->get_param_expr(0)))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery expr is NULL", K(ret)); } else if (OB_ISNULL(subquery = subq_expr->get_ref_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery stmt is NULL", K(ret)); } else if (subquery->is_contains_assignment()) { // do nothing } else if (OB_FAIL(subquery_can_be_eliminated_in_exists(expr->get_expr_type(), subquery, can_be_eliminated, need_add_limit_constraint))) { LOG_WARN("Subquery elimination of select list in EXISTS fails", K(ret)); } else if (!can_be_eliminated) { if (OB_FAIL(eliminate_select_list_in_exists(stmt, expr->get_expr_type(), subquery, trans_happened))) { LOG_WARN("Subquery elimination of select list in EXISTS fails", K(ret)); } else if (OB_FAIL(eliminate_groupby_in_exists(stmt, expr->get_expr_type(), subquery, trans_happened))) { LOG_WARN("Subquery elimination of group by in EXISTS fails", K(ret)); //EXISTS, NOT EXISTS子查询中的order by可以消除 } else if (subquery->get_order_items().count() > 0) { trans_happened = true; subquery->get_order_items().reset(); } if (OB_SUCC(ret) && trans_happened) { subq_expr->set_output_column(subquery->get_select_item_size()); } } } else if (expr->has_flag(IS_WITH_ANY) || expr->has_flag(IS_WITH_ALL)) { if (OB_ISNULL(subq_expr = static_cast(expr->get_param_expr(1))) || OB_ISNULL(left_hand = static_cast(expr->get_param_expr(0)))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery or left_hand expr is NULL", K(ret)); } else if (OB_ISNULL(subquery = subq_expr->get_ref_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery stmt is NULL", K(ret)); } else if (OB_FAIL(eliminate_groupby_in_any_all(subquery, trans_happened))) { LOG_WARN("Subquery elimination of group by in ANY, ALL fails", K(ret)); } else if (!subq_expr->get_exec_params().empty()) { // correlated subquery if (OB_FAIL(eliminate_distinct_in_any_all(subquery, trans_happened))) { LOG_WARN("Subquery elimination of distinct in ANY, ALL fails", K(ret)); } else {/*do nothing*/} } else if (!expr->has_flag(IS_WITH_ANY)) { /*do nothing*/ } else if (OB_FAIL(check_need_add_limit(subquery, check_status))) { LOG_WARN("check need add limit failed", K(ret)); } else if (!check_status) { /*do nothing*/ } else if (OB_FAIL(ObTransformUtils::set_limit_expr(subquery, ctx_))) { LOG_WARN("add limit expr failed", K(ret)); } else { trans_happened = true; } } } return ret; } int ObTransformSimplifySubquery::subquery_can_be_eliminated_in_exists(const ObItemType op_type, const ObSelectStmt *stmt, bool &can_be_eliminated, bool &need_add_limit_constraint) const { int ret = OB_SUCCESS; can_be_eliminated = false; need_add_limit_constraint = false; // 当where subquery满足以下条件即可eliminate(裁剪) // 1. 当前stmt不是set stmt // 2. [not] exists(subq) // 3. have aggr and no group by and no having if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt is NULL", K(ret)); } else if (0 == stmt->get_table_size() || stmt->is_set_stmt()) { // Only non-set stmt will be eliminated and do nothing for other DML stmts: // 1. set -> No elimination // 2. select 1 + floor(2) (table_size == 0) -> No elimination } else if (0 == stmt->get_group_expr_size() && !stmt->has_rollup() && stmt->get_aggr_item_size() > 0 && !stmt->has_having()) { bool has_limit = false; if (OB_FAIL(check_limit(op_type, stmt, has_limit, need_add_limit_constraint))) { LOG_WARN("failed to check subquery has unremovable limit", K(ret)); } else if (!has_limit) { can_be_eliminated = true; } } return ret; } int ObTransformSimplifySubquery::select_list_can_be_eliminated(const ObItemType op_type, const ObSelectStmt *stmt, bool &can_be_eliminated, bool &need_add_limit_constraint) const { int ret = OB_SUCCESS; bool has_limit = false; can_be_eliminated = false; need_add_limit_constraint = false; // 当where subquery满足以下条件即可eliminate(裁剪) // 1. 当前stmt不是set stmt // 2. [not] exists(subq) // 3. scala group by or stmt has having clause // 4. distinct和limit不同时存在 if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt is invalid", K(ret), K(stmt)); } else if (0 == stmt->get_table_size() || stmt->is_set_stmt()) { // Only non-set stmt will be eliminated and do nothing for other DML stmts: // 1. set -> No elimination // 2. select 1 + floor(2) (table_size == 0) -> No elimination } else if ((0 == stmt->get_group_expr_size() && stmt->get_aggr_item_size() > 0) || stmt->has_having()) { /*do nothing*/ } else if (OB_FAIL(check_limit(op_type, stmt, has_limit, need_add_limit_constraint))) { LOG_WARN("failed to check limit", K(ret)); } else if (has_limit && stmt->has_distinct()) { // do nothing } else if (stmt->get_select_item_size() == 1 && NULL != stmt->get_select_item(0).expr_ && stmt->get_select_item(0).expr_->is_const_raw_expr()) { // do nothing } else { can_be_eliminated = true; } return ret; } int ObTransformSimplifySubquery::groupby_can_be_eliminated_in_exists(const ObItemType op_type, const ObSelectStmt *stmt, bool &can_be_eliminated, bool &need_add_limit_constraint) const { int ret = OB_SUCCESS; can_be_eliminated = false; need_add_limit_constraint = false; // 当[not] exists(subq)满足以下所有条件时,可消除group by子句: // 1. 当前stmt不是set stmt // 2. 没有having子句 // 3. 没有limit子句 if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt is NULL", K(ret)); } else if (0 == stmt->get_table_size() || stmt->is_set_stmt()) { // Only non-set stmt will be eliminated and do nothing for other DML stmts: // 1. set -> No elimination // 2. select 1 + floor(2) (table_size == 0) -> No elimination } else if (stmt->has_group_by() && 0 == stmt->get_aggr_item_size() && !stmt->has_having()){ // No having, no limit, no aggr bool has_limit = false; if (OB_FAIL(check_limit(op_type, stmt, has_limit, need_add_limit_constraint))) { LOG_WARN("failed to check subquery has unremovable limit", K(ret)); } else if (!has_limit) { can_be_eliminated = true; } } return ret; } int ObTransformSimplifySubquery::groupby_can_be_eliminated_in_any_all(const ObSelectStmt *stmt, bool &can_be_eliminated) const { int ret = OB_SUCCESS; can_be_eliminated = false; // 当Any/all/in(subq)满足以下所有条件时,可消除group by子句: // 1. 当前stmt不是set stmt // 2. 没有having子句 // 3. 没有limit子句 // 4. 无聚集函数(select item中) // 5. 非常量select item列,全部包含在group exprs中 if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt is NULL", K(ret)); } else if (0 == stmt->get_table_size() || stmt->is_set_stmt()) { // Only non-set stmt will be eliminated and do nothing for other DML stmts: // 1. set -> No elimination // 2. select 1 + floor(2) (table_size == 0) -> No elimination } else if (stmt->has_group_by() && !stmt->has_having() && !stmt->has_limit() && 0 == stmt->get_aggr_item_size()) { // Check if select list is involved in group exprs ObRawExpr *s_expr = NULL; bool all_in_group_exprs = true; for (int i = 0; OB_SUCC(ret) && all_in_group_exprs && i < stmt->get_select_item_size(); ++i) { if (OB_ISNULL(s_expr = stmt->get_select_item(i).expr_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("select list expr is NULL", K(ret)); } else if ((s_expr)->has_flag(CNT_COLUMN)) { if (!ObOptimizerUtil::find_equal_expr(stmt->get_group_exprs(), s_expr)) { all_in_group_exprs = false; } else { /* do nothing */ } } else { /* do nothing */ } } // for if (OB_SUCCESS == ret && all_in_group_exprs) { can_be_eliminated = true; } else { /* do nothing */ } } else { /* do nothing */ } return ret; } int ObTransformSimplifySubquery::eliminate_subquery_in_exists(ObDMLStmt *stmt, ObRawExpr *&expr, bool need_add_limit_constraint, bool &trans_happened) { int ret = OB_SUCCESS; ObRawExprFactory *expr_factory = NULL; ObSelectStmt *subquery = NULL; if (OB_ISNULL(expr) || OB_ISNULL(ctx_) || OB_ISNULL(expr_factory = ctx_->expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("NULL pointer Error", KP(expr), KP_(ctx), KP(expr_factory), K(ret)); } else if (T_OP_EXISTS == expr->get_expr_type() || T_OP_NOT_EXISTS == expr->get_expr_type()) { ObOpRawExpr *op = static_cast(expr); ObQueryRefRawExpr *subq_expr = static_cast(op->get_param_expr(0)); if (OB_ISNULL(subq_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid Query Ref Expr", K(ret)); } else if (OB_ISNULL(subquery = subq_expr->get_ref_stmt())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery stmt is NULL", K(ret)); //Just in case different parameters hit same plan, firstly we need add const param constraint } else if (need_add_limit_constraint && OB_FAIL(ObTransformUtils::add_const_param_constraints(subquery->get_limit_expr(), ctx_))) { LOG_WARN("failed to add const param constraints", K(ret)); } else if (OB_FAIL(ObOptimizerUtil::remove_item(stmt->get_subquery_exprs(), subq_expr))) { LOG_WARN("remove expr failed", K(ret)); } else { ObConstRawExpr *c_expr = NULL; if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*expr_factory, ObIntType, (T_OP_EXISTS == expr->get_expr_type()), c_expr))) { LOG_WARN("failed to create expr", K(ret)); } else if (OB_ISNULL(c_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("create expr error in eliminate_subquery_in_exists()", KP(c_expr), K(ret)); } else if (OB_FAIL(c_expr->formalize(ctx_->session_info_))) { LOG_WARN("failed to formalize a new expr", K(ret)); } else { expr = c_expr; trans_happened = true; } } } return ret; } int ObTransformSimplifySubquery::eliminate_select_list_in_exists(ObDMLStmt *stmt, const ObItemType op_type, ObSelectStmt *subquery, bool &trans_happened) { int ret = OB_SUCCESS; ObRawExprFactory *expr_factory = NULL; if (OB_ISNULL(subquery) || OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(expr_factory = ctx_->expr_factory_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("NULL pointer Error", KP(subquery), KP_(ctx), KP(expr_factory), K(ret)); } else { bool can_be_eliminated = false; bool need_add_limit_constraint = false; if (OB_FAIL(select_list_can_be_eliminated(op_type, subquery, can_be_eliminated, need_add_limit_constraint))) { LOG_WARN("Checking if select list can be eliminated in subquery failed", K(ret)); } else if (can_be_eliminated) { // Add single select item with const int 1 ObConstRawExpr *c_expr = NULL; int64_t const_value = 1; // Clear existing select items first subquery->clear_select_item(); // Clear distinct flag subquery->assign_all(); //reset window function subquery->get_window_func_exprs().reset(); // Clear the aggr items which only appear in select items if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*expr_factory, ObIntType, const_value, c_expr))) { LOG_WARN("failed to create expr", K(ret)); } else if (OB_ISNULL(c_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("create expr error in subquery_select_list_eliminate()", K(c_expr), K(ret)); } else if (OB_FAIL(c_expr->formalize(ctx_->session_info_))) { LOG_WARN("failed to formalize a new expr", K(ret)); } else { SelectItem select_item; select_item.alias_name_ = "1"; select_item.expr_name_ = "1"; select_item.expr_ = c_expr; if (OB_FAIL(subquery->add_select_item(select_item))) { LOG_WARN("Failed to add select item", K(select_item), K(ret)); //Just in case different parameters hit same plan,firstly we need add const param constraint } else if (need_add_limit_constraint && OB_FAIL(ObTransformUtils::add_const_param_constraints(subquery->get_limit_expr(), ctx_))) { LOG_WARN("failed to add const param constraints", K(ret)); } else { trans_happened = true; } } } else { /* do nothing */ } } return ret; } int ObTransformSimplifySubquery::eliminate_groupby_in_exists(ObDMLStmt *stmt, const ObItemType op_type, ObSelectStmt *&subquery, bool &trans_happened) { int ret = OB_SUCCESS; bool can_be_eliminated = false; bool need_add_limit_constraint = false; if (OB_ISNULL(subquery) || OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery is NULL", K(ret)); } else if (OB_FAIL(groupby_can_be_eliminated_in_exists(op_type, subquery, can_be_eliminated, need_add_limit_constraint))) { LOG_WARN("Checking if group by can be eliminated in subquery in exists failed", K(ret)); } else if (can_be_eliminated) { if (subquery->has_group_by()) { // Eliminate group by trans_happened = true; //Just in case different parameters hit same plan, firstly we need add const param constraint if (need_add_limit_constraint && OB_FAIL(ObTransformUtils::add_const_param_constraints(subquery->get_limit_expr(), ctx_))) { LOG_WARN("failed to add const param constraints", K(ret)); } else { subquery->get_group_exprs().reset(); trans_happened = true; } } else { /* do nothing */ } } else { /* do nothing */ } return ret; } int ObTransformSimplifySubquery::eliminate_groupby_in_any_all(ObSelectStmt *&subquery, bool &trans_happened) { int ret = OB_SUCCESS; bool can_be_eliminated = false; if (OB_ISNULL(subquery)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery is NULL", K(ret)); } else if (OB_FAIL(groupby_can_be_eliminated_in_any_all(subquery, can_be_eliminated))) { LOG_WARN("Checking if group by can be eliminated in subquery failed", K(ret)); } else if (can_be_eliminated) { if (subquery->has_group_by()) { // Eliminate group by trans_happened = true; subquery->get_group_exprs().reset(); } else { /* do nothing */ } } else { /* do nothing */ } return ret; } int ObTransformSimplifySubquery::eliminate_distinct_in_any_all(ObSelectStmt *subquery, bool &trans_happened) { int ret = OB_SUCCESS; bool contain_rownum = false; if (OB_ISNULL(subquery)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery is NULL", K(ret)); } else if (subquery->has_limit()) { /*do nothing*/ } else if (OB_FAIL(subquery->has_rownum(contain_rownum))) { LOG_WARN("failed to check subquery has rownum", K(ret)); } else if (contain_rownum) { /*do nothing*/ } else if (subquery->has_distinct()) { subquery->assign_all(); trans_happened = true; } else { /* do nothing */ } return ret; } int ObTransformSimplifySubquery::check_need_add_limit(ObSelectStmt *subquery, bool &need_add_limit) { int ret = OB_SUCCESS; need_add_limit = false; if (OB_ISNULL(subquery)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Subquery is NULL", K(ret)); } else if (subquery->has_limit()) { /*do nothing*/ } else if (subquery->get_from_item_size() > 0) { const ObRawExpr *select_expr = NULL; bool is_const = true; for (int64_t i = 0; OB_SUCC(ret) && is_const && i < subquery->get_select_item_size(); ++i) { const SelectItem &select_item = subquery->get_select_item(i); if (OB_ISNULL(select_expr = select_item.expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("select expr is NULL", K(ret)); } else if (select_expr->is_const_expr()) { /*do nothing*/ } else { is_const = false; } } if (OB_SUCC(ret) && is_const) { need_add_limit = true; } } return ret; } int ObTransformSimplifySubquery::check_limit(const ObItemType op_type, const ObSelectStmt *subquery, bool &has_limit, bool &need_add_limit_constraint) const { int ret = OB_SUCCESS; ObPhysicalPlanCtx *plan_ctx = NULL; bool is_const_select = false; has_limit = false; need_add_limit_constraint = false; if (OB_ISNULL(subquery) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->exec_ctx_) || OB_ISNULL(plan_ctx = ctx_->exec_ctx_->get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(subquery), K(ctx_), K(ctx_->exec_ctx_), K(plan_ctx)); } else if (OB_FAIL(check_const_select(*subquery, is_const_select))) { LOG_WARN("failed to check const select", K(ret)); } else if (op_type != T_OP_EXISTS && op_type != T_OP_NOT_EXISTS && !is_const_select) { has_limit = subquery->has_limit(); } else if (!subquery->has_limit() || subquery->get_offset_expr() != NULL || subquery->get_limit_percent_expr() != NULL) { has_limit = subquery->has_limit(); } else { bool is_null_value = false; int64_t limit_value = 0; if (OB_FAIL(ObTransformUtils::get_limit_value(subquery->get_limit_expr(), subquery, &plan_ctx->get_param_store(), ctx_->exec_ctx_, ctx_->allocator_, limit_value, is_null_value))) { LOG_WARN("failed to get_limit_value", K(ret)); } else if (!is_null_value && limit_value >= 1) { has_limit = false; //Just in case different parameters hit same plan, firstly we need add const param constraint need_add_limit_constraint = true; } else { has_limit = true; } } return ret; } int ObTransformSimplifySubquery::check_const_select(const ObSelectStmt &stmt, bool &is_const_select) const { int ret = OB_SUCCESS; is_const_select = true; for (int64_t i = 0; OB_SUCC(ret) && is_const_select && i < stmt.get_select_item_size(); ++i) { if (OB_ISNULL(stmt.get_select_item(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null", K(ret)); } else { is_const_select = stmt.get_select_item(i).expr_->is_const_expr(); } } return ret; }