add simplify subquery with dual exists rule

This commit is contained in:
ChangerR
2023-07-11 12:24:38 +00:00
committed by ob-robot
parent 6faec38b94
commit 9e6a7c4f6d
2 changed files with 121 additions and 1 deletions

View File

@ -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;
}
}
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<ObQueryRefRawExpr*>(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<ObRawExpr*, 4> 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<ObQueryRefRawExpr*>(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;
}