diff --git a/src/sql/rewrite/ob_transform_simplify_subquery.cpp b/src/sql/rewrite/ob_transform_simplify_subquery.cpp index cacb43ca07..f19359b4bc 100644 --- a/src/sql/rewrite/ob_transform_simplify_subquery.cpp +++ b/src/sql/rewrite/ob_transform_simplify_subquery.cpp @@ -1270,6 +1270,13 @@ int ObTransformSimplifySubquery::eliminate_subquery(ObDMLStmt *stmt, } LOG_TRACE("finish to eliminate subquery", K(can_be_eliminated), K(ret)); + } else if (OB_FAIL(empty_table_subquery_can_be_eliminated_in_exists(expr, can_be_eliminated))) { + LOG_WARN("failed to check empty table subquery can be eliminate", K(ret)); + } else if (can_be_eliminated) { + if (OB_FAIL(do_trans_empty_table_subquery_as_expr(expr, trans_happened))) { + LOG_WARN("failed to do trans empty table subquery as expr", K(ret)); + } + LOG_TRACE("finish to eliminate empty table subquery", K(ret)); } else if (!can_be_eliminated) { if (OB_FAIL(simplify_select_items(stmt, expr->get_expr_type(), subquery, false, trans_happened))) { LOG_WARN("Simplify select items in EXISTS fails", K(ret)); @@ -2224,6 +2231,8 @@ int ObTransformSimplifySubquery::check_stmt_can_trans_as_exists(ObSelectStmt *st } 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_; @@ -2425,4 +2434,111 @@ int ObTransformSimplifySubquery::try_trans_any_all_as_exists( } } return ret; -} \ No newline at end of file +} + +int ObTransformSimplifySubquery::empty_table_subquery_can_be_eliminated_in_exists(ObRawExpr *expr, + bool &is_valid) +{ + int ret = OB_SUCCESS; + ObQueryRefRawExpr* query_ref = NULL; + ObSelectStmt* ref_stmt = NULL; + bool contain_rownum = false; + bool has_limit = false; + is_valid = false; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (T_OP_EXISTS != expr->get_expr_type() && + T_OP_NOT_EXISTS != expr->get_expr_type()) { + is_valid = false; + } else if (OB_UNLIKELY(expr->get_param_count() != 1) || + OB_ISNULL(expr->get_param_expr(0)) || + OB_UNLIKELY(!expr->get_param_expr(0)->is_query_ref_expr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected exists/not exists expr", K(ret)); + } else if (OB_FALSE_IT(query_ref = static_cast(expr->get_param_expr(0)))) { + } else if (OB_ISNULL(ref_stmt = query_ref->get_ref_stmt())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected ref stmt", K(ret)); + } else if (OB_FAIL(ref_stmt->has_rownum(contain_rownum))) { + LOG_WARN("failed to check ref stmt has rownum", K(ret)); + } else if (OB_FAIL(check_limit(expr->get_expr_type(), ref_stmt, has_limit))) { + LOG_WARN("failed to check limit", K(ret)); + } else if (contain_rownum || has_limit) { + is_valid = false; + } else if (query_ref->get_ref_count() > 1) { + is_valid = false; + } else if (0 != ref_stmt->get_from_item_size() || + 0 == ref_stmt->get_condition_size() || + ref_stmt->is_set_stmt() || + ref_stmt->is_contains_assignment() || + ref_stmt->has_group_by() || + ref_stmt->has_having() || + ref_stmt->is_hierarchical_query() || + ref_stmt->has_sequence() || + ref_stmt->has_window_function()) { + is_valid = false; + } else { + is_valid = true; + } + return ret; +} + +int ObTransformSimplifySubquery::do_trans_empty_table_subquery_as_expr(ObRawExpr *&expr, + bool &trans_happened) +{ + int ret = OB_SUCCESS; + ObQueryRefRawExpr* query_ref = NULL; + ObSelectStmt* ref_stmt = NULL; + bool add_limit_constraint = false; + ObSEArray conditions; + ObRawExpr *out_expr = NULL; + trans_happened = false; + if (OB_ISNULL(expr) || + OB_ISNULL(ctx_) || + OB_ISNULL(ctx_->expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_UNLIKELY(expr->get_param_count() != 1) || + OB_ISNULL(expr->get_param_expr(0)) || + OB_UNLIKELY(!expr->get_param_expr(0)->is_query_ref_expr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected exists/not exists expr", K(ret)); + } else if (OB_FALSE_IT(query_ref = static_cast(expr->get_param_expr(0)))) { + } else if (OB_ISNULL(ref_stmt = query_ref->get_ref_stmt())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected ref stmt", K(ret)); + } else if (OB_FAIL(need_add_limit_constraint(expr->get_expr_type(), ref_stmt, add_limit_constraint))){ + LOG_WARN("failed to check limit constraints", K(ret)); + } else if (add_limit_constraint && + OB_FAIL(ObTransformUtils::add_const_param_constraints(ref_stmt->get_limit_expr(), ctx_))) { + LOG_WARN("failed to add const param constraints", K(ret)); + } else if (OB_FAIL(conditions.assign(ref_stmt->get_condition_exprs()))) { + LOG_WARN("failed to assign condition exprs", K(ret)); + } else if (ObTransformUtils::decorrelate(conditions, query_ref->get_exec_params())) { + LOG_WARN("failed to decorrelate condition exprs", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_and_expr(*ctx_->expr_factory_, + conditions, + out_expr))) { + LOG_WARN("failed to formalize expr", K(ret)); + } else if (OB_ISNULL(out_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (T_OP_NOT_EXISTS == expr->get_expr_type() && + OB_FAIL(ObRawExprUtils::build_lnnvl_expr(*ctx_->expr_factory_, + out_expr, + out_expr))) { + LOG_WARN("failed to build lnnvl expr", K(ret)); + } else if (OB_ISNULL(out_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(out_expr->formalize(ctx_->session_info_))) { + LOG_WARN("failed to formalize expr", K(ret)); + } else if (OB_FAIL(out_expr->pull_relation_id())) { + LOG_WARN("failed to pull relation id", K(ret)); + } else { + expr = out_expr; + trans_happened = true; + } + return ret; +} diff --git a/src/sql/rewrite/ob_transform_simplify_subquery.h b/src/sql/rewrite/ob_transform_simplify_subquery.h index bc6830c7a9..5efa493d18 100644 --- a/src/sql/rewrite/ob_transform_simplify_subquery.h +++ b/src/sql/rewrite/ob_transform_simplify_subquery.h @@ -217,6 +217,10 @@ private: ObNotNullContext *not_null_cxt, bool is_bool_expr, bool &trans_happened); + int empty_table_subquery_can_be_eliminated_in_exists(ObRawExpr *expr, + bool &is_valid); + int do_trans_empty_table_subquery_as_expr(ObRawExpr *&expr, + bool &trans_happened); }; }