2587 lines
107 KiB
C++
2587 lines
107 KiB
C++
/**
|
|
* 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<ObParentDMLStmt> &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;
|
|
OPT_TRACE("push down outer join condition:", 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;
|
|
OPT_TRACE("transform subquery to expr:", 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;
|
|
OPT_TRACE("remove simple select:", 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;
|
|
OPT_TRACE("transform not expr:", 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;
|
|
OPT_TRACE("add limit for exists subquery:", 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;
|
|
OPT_TRACE("simply any/all subquery:", 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;
|
|
OPT_TRACE("simply exists subquery:", is_happened);
|
|
LOG_TRACE("succeed to transform_exists_query", K(is_happened));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(transform_any_all_as_exists(stmt, is_happened))) {
|
|
LOG_WARN("failed to transform_any_all_as_exists", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
OPT_TRACE("transform any/all as exists/not exists:", is_happened);
|
|
LOG_TRACE("succeed to transform_any_all_as_exists", K(is_happened));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && trans_happened) {
|
|
if (OB_FAIL(stmt->adjust_subquery_list())) {
|
|
LOG_WARN("failed to adjust subquery list", K(ret));
|
|
} else if (OB_FAIL(stmt->formalize_query_ref_exprs())) {
|
|
LOG_WARN("failed to formalize query ref exprs");
|
|
} else 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;
|
|
trans_happened = false;
|
|
ObSEArray<ObRawExprPointer, 16> 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->is_alias_ref_expr()) {
|
|
// 如果 expr 的param 必须是 subquery,那么不去改写它包含的子查询
|
|
//do nothing
|
|
} else if (expr->is_query_ref_expr() &&
|
|
!static_cast<ObQueryRefRawExpr *>(expr)->is_multiset()) {
|
|
//如果是 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<ObQueryRefRawExpr *>(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, query_ref->get_exec_params()))) {
|
|
LOG_WARN("failed to decorrleation expr", 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<ObRawExpr *, 1> old_expr;
|
|
ObSEArray<ObRawExpr *, 1> 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_relation_exprs(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()
|
|
&& !stmt->has_sequence()) {
|
|
is_valid = true;
|
|
}
|
|
if (OB_SUCC(ret) && is_valid) {
|
|
if (OB_ISNULL(stmt->get_select_item(0).expr_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("stmt is null", K(ret), K(stmt));
|
|
} else if (stmt->get_select_item(0).expr_->is_const_expr()) {
|
|
// do nothing
|
|
} else if (stmt->get_select_item(0).expr_->has_flag(CNT_PL_UDF)) {
|
|
is_valid = false;
|
|
}
|
|
}
|
|
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;
|
|
bool is_happened = false;
|
|
trans_happened = false;
|
|
ObSEArray<ObRawExprPointer, 16> 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(do_transform_not_expr(expr, is_happened))) {
|
|
LOG_WARN("failed to transform expr", K(ret));
|
|
} else if (!is_happened) {
|
|
// do nothing
|
|
} else if (OB_FAIL(relation_expr_pointers.at(i).set(expr))) {
|
|
LOG_WARN("failed to set expr", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::do_transform_not_expr(ObRawExpr *&expr, bool &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObRawExpr *param = NULL;
|
|
ObItemType expr_type = T_INVALID;
|
|
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), K(*param));
|
|
} else if (expr->get_expr_type() != T_OP_NOT ||
|
|
!expr->has_flag(CNT_SUB_QUERY)) {
|
|
// do nothing
|
|
} else if (OB_ISNULL(param = expr->get_param_expr(0))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(*param));
|
|
} else if (OB_FALSE_IT(expr_type = param->get_expr_type())) {
|
|
} 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(ctx_->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<ObOpRawExpr *>(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<ObOpRawExpr *>(param)->get_param_exprs()))) {
|
|
LOG_WARN("failed to append param exprs", K(ret));
|
|
} else if (OB_FAIL(new_op_expr->formalize(ctx_->session_info_))) {
|
|
LOG_WARN("failed to formalize expr", K(ret));
|
|
} else {
|
|
expr = new_op_expr;
|
|
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<ObSelectStmt *>(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<ObQueryRefRawExpr *>(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 {
|
|
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 {
|
|
ObIArray<JoinedTable *> &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<JoinedTable*>(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;
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::get_push_down_conditions(ObDMLStmt *stmt,
|
|
JoinedTable *join_table,
|
|
ObIArray<ObRawExpr *> &join_conds,
|
|
ObIArray<ObRawExpr *> &push_down_conds) {
|
|
int ret = OB_SUCCESS;
|
|
ObSqlBitSet<> right_table_ids;
|
|
if (OB_ISNULL(stmt) || OB_ISNULL(join_table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected NULL", K(ret));
|
|
} 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));
|
|
}
|
|
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < join_conds.count(); ++i) {
|
|
ObSEArray<ObQueryRefRawExpr *, 4> query_refs;
|
|
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)) {
|
|
// do nothing
|
|
} else if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(join_conds.at(i), query_refs))) {
|
|
LOG_WARN("extract_query_ref_expr failed", K(ret), K(join_conds), K(i));
|
|
} else {
|
|
bool can_push_down = false;
|
|
for (int64_t j = 0; OB_SUCC(ret) && j < query_refs.count(); ++j) {
|
|
if (OB_ISNULL(query_refs.at(j))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected NULL", K(ret));
|
|
} else if (query_refs.at(j)->get_ref_count() == 1){
|
|
can_push_down = true;
|
|
} else {
|
|
can_push_down = false;
|
|
}
|
|
}
|
|
|
|
if (can_push_down && OB_FAIL(push_down_conds.push_back(join_conds.at(i)))) {
|
|
LOG_WARN("failed to push back expr", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// 当 left join 右表为 basic/generate/join table 时
|
|
// 对 on condition 中包含 subquery(要求ref_count = 1)仅包含本层右表列的条件进行下压:
|
|
// 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;
|
|
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 {
|
|
ObSEArray<ObRawExpr*, 16> push_down_conds;
|
|
TableItem *view_item = NULL;
|
|
TableItem *right_table = join_table->right_table_;
|
|
if (OB_FAIL(get_push_down_conditions(stmt,
|
|
join_table,
|
|
join_table->get_join_conditions(),
|
|
push_down_conds))) {
|
|
LOG_WARN("failed to get_push_down_conditions", K(ret), K(join_table));
|
|
} else if (push_down_conds.empty()) {
|
|
/*do nothing*/
|
|
} else if (ObOptimizerUtil::remove_item(join_table->get_join_conditions(), push_down_conds)) {
|
|
LOG_WARN("failed to remove item", K(ret));
|
|
} else if (OB_FAIL(ObTransformUtils::replace_with_empty_view(ctx_,
|
|
stmt,
|
|
view_item,
|
|
right_table))) {
|
|
LOG_WARN("failed to create empty view table", K(ret));
|
|
} else if (OB_FAIL(ObTransformUtils::create_inline_view(ctx_,
|
|
stmt,
|
|
view_item,
|
|
right_table,
|
|
&push_down_conds))) {
|
|
LOG_WARN("failed to create inline view", K(ret));
|
|
} else {
|
|
trans_happened = true;
|
|
}
|
|
}
|
|
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<ObRawExpr*, 16> 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<ObOpRawExpr*>(expr);
|
|
ObQueryRefRawExpr *subq_expr = static_cast<ObQueryRefRawExpr *>(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<ObRawExprPointer, 16> 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(eliminate_groupby_distinct_in_any_all(expr, is_happened))) {
|
|
LOG_WARN("failed to eliminate groupby distinct in any all", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else 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;
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(add_limit_for_any_all_subquery(expr, is_happened))) {
|
|
LOG_WARN("failed to add limit for any all subquery", 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<ObQueryRefRawExpr*>(
|
|
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<ObColumnRefRawExpr *>(sel_expr);
|
|
bool is_nullable = true;
|
|
bool is_match = false;
|
|
ObArenaAllocator alloc;
|
|
EqualSets &equal_sets = ctx_->equal_sets_;
|
|
ObSEArray<ObRawExpr *, 4> const_exprs;
|
|
if (OB_FAIL(child_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(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<ObQueryRefRawExpr*>(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 (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())) {
|
|
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<ObQueryRefRawExpr*>(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<ObQueryRefRawExpr*>(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())) {
|
|
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<ObRawExprPointer, 16> relation_expr_pointers;
|
|
if (OB_ISNULL(stmt)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("stmt is NULL", K(ret));
|
|
} else if (!stmt->has_subquery()) {
|
|
// 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;
|
|
bool is_happened = false;
|
|
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_eliminate_subquery(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_eliminate_subquery(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:
|
|
} else if (expr->has_flag(CNT_ROWNUM)) {
|
|
/*do nothing */
|
|
} else if (OB_FAIL(recursive_eliminate_subquery(stmt, expr, trans_happened))) {
|
|
LOG_WARN("failed to recursive eliminate subquery", KP(expr), K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::recursive_eliminate_subquery(ObDMLStmt *stmt,
|
|
ObRawExpr *&expr,
|
|
bool &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_stack_overflow = false;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
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),
|
|
trans_happened)))) {
|
|
LOG_WARN("failed to recursive eliminate subquery", K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && OB_FAIL(eliminate_subquery(stmt, expr, trans_happened))) {
|
|
LOG_WARN("failed to eliminate subquery", K(ret));
|
|
}
|
|
} else { /*do nothing*/ }
|
|
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 &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool can_be_eliminated = false;
|
|
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<ObQueryRefRawExpr *>(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() || subquery->is_values_table_query()) {
|
|
// do nothing
|
|
} else if (OB_FAIL(subquery_can_be_eliminated_in_exists(expr->get_expr_type(),
|
|
subquery,
|
|
can_be_eliminated))) {
|
|
LOG_WARN("Subquery elimination of select list in EXISTS fails", K(ret));
|
|
} else if (can_be_eliminated){
|
|
if (OB_FAIL(eliminate_subquery_in_exists(stmt, expr, trans_happened))) {
|
|
LOG_WARN("failed to eliminate subquery in exists", K(ret), KP(expr));
|
|
}
|
|
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));
|
|
} 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());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::subquery_can_be_eliminated_in_exists(const ObItemType op_type,
|
|
const ObSelectStmt *stmt,
|
|
bool &can_be_eliminated) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
can_be_eliminated = false;
|
|
if (OB_ISNULL(stmt)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("stmt is NULL", K(ret));
|
|
} else if (stmt->is_set_stmt()) {
|
|
if (ObSelectStmt::UNION == stmt->get_set_op() && !stmt->is_recursive_union()) {
|
|
const ObIArray<ObSelectStmt*> &child_stmts = stmt->get_set_query();
|
|
//loop child stmts and if one of them can be eliminated, then eliminate the whole set_stmt
|
|
for (int64_t i = 0; OB_SUCC(ret) && !can_be_eliminated && i < child_stmts.count(); ++i) {
|
|
ObSelectStmt *child = child_stmts.at(i);
|
|
if (OB_FAIL(SMART_CALL(subquery_can_be_eliminated_in_exists(op_type, child, can_be_eliminated)))) {
|
|
LOG_WARN("Subquery elimination of select list in EXISTS fails", K(ret));
|
|
}
|
|
}
|
|
} else {
|
|
/* other type of set query can no be eliminated */
|
|
}
|
|
} else if (is_subquery_not_empty(*stmt)) {
|
|
bool has_limit = false;
|
|
if (OB_FAIL(check_limit(op_type, stmt, has_limit))) {
|
|
LOG_WARN("failed to check subquery has unremovable limit", K(ret));
|
|
} else if (!has_limit) {
|
|
can_be_eliminated = true;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObTransformSimplifySubquery::is_subquery_not_empty(const ObSelectStmt &stmt) {
|
|
|
|
/*
|
|
situation 1:
|
|
select 1+1 -> can be simplify
|
|
select 1+1 from dual having 0 -> not satisfy
|
|
select 1+1 from dual where 1=0 -> not satisfy
|
|
select 1+1 from dual limit 0 -> not satisfy but limit will be checked later
|
|
situation 2:
|
|
select max(c1) from t1 ->always not empty
|
|
*/
|
|
|
|
return (0 == stmt.get_table_size()
|
|
&& 0 == stmt.get_having_expr_size()
|
|
&& 0 == stmt.get_condition_size())
|
|
|| (0 == stmt.get_group_expr_size()
|
|
&& !stmt.has_rollup()
|
|
&& stmt.get_aggr_item_size() > 0
|
|
&& !stmt.has_having());
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::select_items_can_be_simplified(const ObItemType op_type,
|
|
const ObSelectStmt *stmt,
|
|
bool &can_be_simplified) const
|
|
{
|
|
/*
|
|
* 1. calculate max_select_item_size
|
|
* 1.1 for set stmt, it depends on its child stmt, so only consider its child stmt
|
|
* 2. decide whether need to simplify select_item
|
|
* 2.1 for set stmt, if all child stmt can be simplied, then the union set stmt
|
|
* get max_select_item_size = 1(max_select_item_size will never be updated)
|
|
* 2.2 any of one child stmt can be simplifed , the whole union set stmt can be simplified
|
|
*
|
|
*/
|
|
int ret = OB_SUCCESS;
|
|
bool has_limit = false;
|
|
can_be_simplified = false;
|
|
if (OB_ISNULL(stmt)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("stmt is invalid", K(ret), K(stmt));
|
|
} else if (stmt->is_set_stmt() &&
|
|
(ObSelectStmt::INTERSECT == stmt->get_set_op() ||
|
|
ObSelectStmt::EXCEPT == stmt->get_set_op() ||
|
|
stmt->is_recursive_union())) {
|
|
//do nothing
|
|
} else if (OB_FAIL(check_limit(op_type, stmt, has_limit))) {
|
|
LOG_WARN("failed to check limit", K(ret));
|
|
} else if (has_limit &&
|
|
(stmt->has_distinct() ||
|
|
(stmt->is_set_stmt() && stmt->is_set_distinct()))) {
|
|
/*
|
|
create table t1(a int);
|
|
insert into t1 values (1),(2),(3),(4);
|
|
select distinct 1 from t1 limit 1 offset 3; // is empty
|
|
select distinct a from t1 limit 1 offset 3; // not empty
|
|
*/
|
|
} 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_simplified = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::groupby_can_be_eliminated_in_exists(const ObItemType op_type,
|
|
const ObSelectStmt *stmt,
|
|
bool &can_be_eliminated) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
can_be_eliminated = 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))) {
|
|
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()
|
|
&& !stmt->is_values_table_query()) {
|
|
// 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_item(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 &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObRawExprFactory *expr_factory = NULL;
|
|
ObSelectStmt *subquery = NULL;
|
|
bool add_limit_constraint = false;
|
|
if (OB_ISNULL(expr) || OB_ISNULL(ctx_) || OB_ISNULL(expr_factory = ctx_->expr_factory_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
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<ObOpRawExpr*>(expr);
|
|
ObQueryRefRawExpr *subq_expr = static_cast<ObQueryRefRawExpr *>(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));
|
|
} else if (subquery->is_values_table_query()) { /* do nothing */
|
|
//Just in case different parameters hit same plan, firstly we need add const param constraint
|
|
} else if (OB_FAIL(need_add_limit_constraint(expr->get_expr_type(), subquery, add_limit_constraint))){
|
|
LOG_WARN("failed to check limit constraints", K(ret));
|
|
} else if (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 {
|
|
ObRawExpr *c_expr = NULL;
|
|
if (OB_FAIL(ObRawExprUtils::build_const_bool_expr(expr_factory, c_expr, (T_OP_EXISTS == expr->get_expr_type())))) {
|
|
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::simplify_select_items(ObDMLStmt *stmt,
|
|
const ObItemType op_type,
|
|
ObSelectStmt *subquery,
|
|
bool parent_is_set_query,
|
|
bool &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool has_limit = false;
|
|
ObRawExprFactory *expr_factory = NULL;
|
|
bool can_be_simplified = false;
|
|
if (OB_ISNULL(subquery) || OB_ISNULL(stmt) || OB_ISNULL(ctx_) ||
|
|
OB_ISNULL(expr_factory = ctx_->expr_factory_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL pointer Error", KP(subquery), KP_(ctx), KP(expr_factory), K(ret));
|
|
} else if (OB_FAIL(select_items_can_be_simplified(op_type,
|
|
subquery,
|
|
can_be_simplified))) {
|
|
LOG_WARN("Checking if select list can be eliminated in subquery failed", K(ret));
|
|
} else if (!can_be_simplified) {
|
|
//do nothing
|
|
} else if (ObSelectStmt::UNION == subquery->get_set_op() && !subquery->is_recursive_union()) {
|
|
const ObIArray<ObSelectStmt*> &child_stmts = subquery->get_set_query();
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) {
|
|
ObSelectStmt *child = child_stmts.at(i);
|
|
if (OB_FAIL(SMART_CALL(simplify_select_items(stmt, op_type, child, true, trans_happened)))) {
|
|
LOG_WARN("Simplify select list in EXISTS fails", K(ret));
|
|
}
|
|
}
|
|
ObExprResType res_type;
|
|
res_type.set_type(ObIntType);
|
|
for(int64_t i = 0; OB_SUCC(ret) && i < subquery->get_select_item_size(); i++) {
|
|
SelectItem &select_item = subquery->get_select_item(i);
|
|
if(OB_ISNULL(select_item.expr_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null select expr", K(ret), K(select_item));
|
|
} else {
|
|
select_item.expr_->set_result_type(res_type);
|
|
}
|
|
}
|
|
bool has_limit = false;
|
|
bool add_limit_constraint = false;
|
|
if (OB_FAIL(ret)){
|
|
|
|
} else if (OB_FAIL(check_limit(op_type, subquery, has_limit))) {
|
|
LOG_WARN("failed to check subquery has unremovable limit", K(ret));
|
|
} else if(OB_FAIL(need_add_limit_constraint(op_type, subquery, add_limit_constraint))){
|
|
LOG_WARN("failed to check limit constraints", K(ret));
|
|
} else if(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 (!has_limit) {
|
|
subquery->assign_set_all();
|
|
}
|
|
} else {
|
|
// Add single select item with const int 1
|
|
int64_t const_value = 1;
|
|
ObSEArray<ObAggFunRawExpr*, 8> aggr_items_in_having;
|
|
int max_select_item_size = parent_is_set_query ? subquery->get_select_item_size() : 1;
|
|
subquery->clear_select_item();
|
|
//save aggr item in having
|
|
subquery->clear_aggr_item();
|
|
if (OB_FAIL(ObTransformUtils::extract_aggr_expr(subquery->get_having_exprs(),aggr_items_in_having))) {
|
|
LOG_WARN("failed to get aggr items", K(ret));
|
|
} else if (OB_FAIL(append_array_no_dup(subquery->get_aggr_items(),aggr_items_in_having))) {
|
|
LOG_WARN("failed to remove item", K(ret));
|
|
}
|
|
// Clear distinct flag
|
|
subquery->assign_all();
|
|
//reset window function
|
|
subquery->get_window_func_exprs().reset();
|
|
for(int64_t i = 0; OB_SUCC(ret) && i < max_select_item_size; i++) {
|
|
ObConstRawExpr *c_expr = NULL;
|
|
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 simplify select item", 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 {
|
|
trans_happened = true;
|
|
}
|
|
}
|
|
}
|
|
bool add_limit_constraint = false;
|
|
if (OB_FAIL(ret)) {
|
|
|
|
} else if(OB_FAIL(need_add_limit_constraint(op_type, subquery, add_limit_constraint))){
|
|
LOG_WARN("failed to check limit constraints", K(ret));
|
|
} else if(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));
|
|
}
|
|
}
|
|
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;
|
|
if (OB_ISNULL(subquery) || OB_ISNULL(stmt)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Subquery is NULL", K(ret));
|
|
} else if (subquery->is_set_stmt()) {
|
|
// for set stmt, it should consider whether its child stmt can remove groupby
|
|
if (!subquery->is_recursive_union()) {
|
|
const ObIArray<ObSelectStmt*> &child_stmts = subquery->get_set_query();
|
|
//loop child stmts and if one of them can be eliminated
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) {
|
|
ObSelectStmt *child = child_stmts.at(i);
|
|
if (OB_FAIL(SMART_CALL(eliminate_groupby_in_exists(stmt,op_type, child, trans_happened)))) {
|
|
LOG_WARN("eliminate groupby in child stmt of set query fails", K(ret));
|
|
}
|
|
}
|
|
} else {
|
|
/* union-recursive set stmt not consider */
|
|
}
|
|
} else if (OB_FAIL(groupby_can_be_eliminated_in_exists(op_type, subquery, can_be_eliminated))) {
|
|
LOG_WARN("Checking if group by can be eliminated in subquery in exists failed", K(ret));
|
|
} else if (!can_be_eliminated) {
|
|
/*do nothing*/
|
|
} else if (subquery->has_group_by()) {
|
|
// Eliminate group by
|
|
trans_happened = true;
|
|
bool add_limit_constraint = false;
|
|
//Just in case different parameters hit same plan, firstly we need add const param constraint
|
|
if(OB_FAIL(need_add_limit_constraint(op_type, subquery, add_limit_constraint))){
|
|
LOG_WARN("failed to check limit constraints", K(ret));
|
|
} else if (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 */ }
|
|
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_groupby_distinct_in_any_all(ObRawExpr *expr, bool &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObQueryRefRawExpr *subq_expr = NULL;
|
|
ObSelectStmt *subquery = NULL;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("get unexpected null", K(ret), K(expr));
|
|
} else if (!expr->has_flag(IS_WITH_ALL) && !expr->has_flag(IS_WITH_ANY)) {
|
|
} else if (OB_UNLIKELY(2 != expr->get_param_count())
|
|
|| OB_UNLIKELY(!expr->get_param_expr(1)->is_query_ref_expr())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected expr", K(ret), KPC(expr));
|
|
} else if (OB_ISNULL(subq_expr = static_cast<ObQueryRefRawExpr *>(expr->get_param_expr(1))) ||
|
|
OB_ISNULL(static_cast<ObRawExpr *>(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*/}
|
|
}
|
|
|
|
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::add_limit_for_any_all_subquery(ObRawExpr *expr, bool &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObQueryRefRawExpr *subq_expr = NULL;
|
|
ObSelectStmt *subquery = NULL;
|
|
bool check_status = false;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (!expr->has_flag(IS_WITH_ANY)) {
|
|
/*do nothing*/
|
|
} else if (OB_ISNULL(subq_expr = static_cast<ObQueryRefRawExpr *>(expr->get_param_expr(1)))
|
|
|| OB_ISNULL(static_cast<ObRawExpr *>(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 (subq_expr->has_exec_param()) {
|
|
//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::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::need_add_limit_constraint(const ObItemType op_type,
|
|
const ObSelectStmt *subquery,
|
|
bool &add_limit_constraint) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPhysicalPlanCtx *plan_ctx = NULL;
|
|
bool is_const_select = false;
|
|
bool has_limit = false;
|
|
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(),
|
|
&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
|
|
add_limit_constraint = true;
|
|
} else {
|
|
has_limit = true;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
int ObTransformSimplifySubquery::check_limit(const ObItemType op_type,
|
|
const ObSelectStmt *subquery,
|
|
bool &has_limit) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPhysicalPlanCtx *plan_ctx = NULL;
|
|
bool is_const_select = false;
|
|
has_limit = 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) {
|
|
//not limit
|
|
//limit 1,3
|
|
//limit 20%
|
|
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(),
|
|
&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) {
|
|
//limit n
|
|
has_limit = false;
|
|
} else {
|
|
//limit 0
|
|
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;
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::try_trans_any_all_as_exists(ObDMLStmt *stmt,
|
|
ObRawExpr *&expr,
|
|
ObNotNullContext *not_null_ctx,
|
|
bool is_bool_expr,
|
|
bool &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_valid = false;
|
|
bool is_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(check_can_trans_as_exists(expr, is_bool_expr, 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))) {
|
|
LOG_WARN("failed to do trans any all as exists", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
} else if (!expr->has_flag(CNT_SUB_QUERY)) {
|
|
// do nothing
|
|
} else if (expr->get_expr_type() == T_OP_CASE) {
|
|
ObCaseOpRawExpr* case_expr = static_cast<ObCaseOpRawExpr*>(expr);
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < case_expr->get_when_expr_size(); ++i) {
|
|
if (OB_FAIL(SMART_CALL(try_trans_any_all_as_exists(stmt,
|
|
case_expr->get_when_param_expr(i),
|
|
not_null_ctx,
|
|
true,
|
|
is_happened)))) {
|
|
LOG_WARN("failed to try_transform_any_all for param", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < case_expr->get_then_expr_size(); ++i) {
|
|
if (OB_FAIL(SMART_CALL(try_trans_any_all_as_exists(stmt,
|
|
case_expr->get_then_param_expr(i),
|
|
not_null_ctx,
|
|
false,
|
|
is_happened)))) {
|
|
LOG_WARN("failed to try_transform_any_all for param", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_NOT_NULL(case_expr->get_default_param_expr()) &&
|
|
OB_FAIL(SMART_CALL(try_trans_any_all_as_exists(
|
|
stmt,
|
|
case_expr->get_default_param_expr(),
|
|
not_null_ctx,
|
|
false,
|
|
is_happened)))) {
|
|
LOG_WARN("failed to try_transform_any_all for param", K(ret));
|
|
} else if (OB_FALSE_IT(trans_happened |= is_happened)) {
|
|
//do nothing
|
|
} else if (OB_NOT_NULL(case_expr->get_arg_param_expr()) &&
|
|
OB_FAIL(SMART_CALL(try_trans_any_all_as_exists(
|
|
stmt,
|
|
case_expr->get_arg_param_expr(),
|
|
not_null_ctx,
|
|
false,
|
|
is_happened)))) {
|
|
LOG_WARN("failed to try_transform_any_all for param", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
} else {
|
|
//check children
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) {
|
|
if (OB_FAIL(SMART_CALL(try_trans_any_all_as_exists(stmt,
|
|
expr->get_param_expr(i),
|
|
not_null_ctx,
|
|
false,
|
|
is_happened)))) {
|
|
LOG_WARN("failed to try_transform_any_all for param", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
}
|
|
}
|
|
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<ObRawExpr*, 4> left_exprs;
|
|
ObOpRawExpr* exists_expr = NULL;
|
|
ObItemType cmp_type = T_INVALID;
|
|
ObSEArray<ObRawExpr*, 4> constraints;
|
|
ObSEArray<ObRawExpr*, 4> 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<ObQueryRefRawExpr *>(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<ObOpRawExpr *>(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<ObQueryRefRawExpr*>(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_)) {
|
|
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()) {
|
|
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<ObRawExpr *, 4> 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<ObColumnRefRawExpr *>(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;
|
|
bool is_happened = false;
|
|
if (OB_ISNULL(stmt) ||
|
|
OB_ISNULL(ctx_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else {
|
|
ObNotNullContext not_null_ctx(*ctx_, stmt);
|
|
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_joined_tables().count(); ++i) {
|
|
if (OB_FAIL(transform_any_all_as_exists_joined_table(stmt,
|
|
stmt->get_joined_tables().at(i),
|
|
is_happened))) {
|
|
LOG_WARN("failed to flatten join condition exprs", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FALSE_IT(not_null_ctx.reset())) {
|
|
} else if (OB_FAIL(not_null_ctx.generate_stmt_context(NULLABLE_SCOPE::NS_WHERE))) {
|
|
LOG_WARN("failed to generate where context", K(ret));
|
|
} else if (OB_FAIL(try_trans_any_all_as_exists(stmt,
|
|
stmt->get_condition_exprs(),
|
|
¬_null_ctx,
|
|
true,
|
|
is_happened))) {
|
|
LOG_WARN("failed to trans any all as exists", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
|
|
if (OB_SUCC(ret) && stmt->is_select_stmt()) {
|
|
ObSelectStmt *select_stmt = static_cast<ObSelectStmt*>(stmt);
|
|
not_null_ctx.reset();
|
|
if (OB_FAIL(not_null_ctx.generate_stmt_context(NULLABLE_SCOPE::NS_TOP))) {
|
|
LOG_WARN("failed to generate where context", K(ret));
|
|
} else if (OB_FAIL(try_trans_any_all_as_exists(stmt,
|
|
select_stmt->get_having_exprs(),
|
|
¬_null_ctx,
|
|
true,
|
|
is_happened))) {
|
|
LOG_WARN("failed to try trans any all as exists", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt->get_select_items().count(); ++i) {
|
|
if (OB_ISNULL(select_stmt->get_select_items().at(i).expr_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (OB_FAIL(try_trans_any_all_as_exists(stmt,
|
|
select_stmt->get_select_items().at(i).expr_,
|
|
¬_null_ctx,
|
|
false,
|
|
is_happened))) {
|
|
LOG_WARN("failed to try trans any all as exists", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::transform_any_all_as_exists_joined_table(
|
|
ObDMLStmt* stmt,
|
|
TableItem *table,
|
|
bool &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
JoinedTable *join_table = NULL;
|
|
TableItem *left_table = NULL;
|
|
TableItem *right_table = NULL;
|
|
trans_happened = false;
|
|
bool cur_happened = false;
|
|
bool left_happened = false;
|
|
bool right_happened = false;
|
|
if (OB_ISNULL(table) ) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(table));
|
|
} else if (!table->is_joined_table()) {
|
|
/*do nothing*/
|
|
} else if (OB_ISNULL(join_table = static_cast<JoinedTable*>(table)) ||
|
|
OB_ISNULL(left_table = join_table->left_table_) ||
|
|
OB_ISNULL(right_table = join_table->right_table_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(join_table));
|
|
} else {
|
|
ObNotNullContext not_null_ctx(*ctx_, stmt);
|
|
if (left_table->is_joined_table() &&
|
|
OB_FAIL(not_null_ctx.add_joined_table(static_cast<JoinedTable *>(left_table)))) {
|
|
LOG_WARN("failed to add context", K(ret));
|
|
} else if (right_table->is_joined_table() &&
|
|
OB_FAIL(not_null_ctx.add_joined_table(static_cast<JoinedTable *>(right_table)))) {
|
|
LOG_WARN("failed to add context", K(ret));
|
|
} else if (OB_FAIL(not_null_ctx.add_filter(join_table->get_join_conditions()))) {
|
|
LOG_WARN("failed to add null reject conditions", K(ret));
|
|
} else if (OB_FAIL(try_trans_any_all_as_exists(stmt, join_table->get_join_conditions(),
|
|
¬_null_ctx, true, cur_happened))) {
|
|
LOG_WARN("failed to try trans any all as exists", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(transform_any_all_as_exists_joined_table(stmt,
|
|
join_table->left_table_,
|
|
left_happened)))) {
|
|
LOG_WARN("failed to flatten left child join condition exprs", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(transform_any_all_as_exists_joined_table(stmt,
|
|
join_table->right_table_,
|
|
right_happened)))) {
|
|
LOG_WARN("failed to flatten right child join condition exprs", K(ret));
|
|
} else {
|
|
trans_happened = cur_happened | left_happened | right_happened;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformSimplifySubquery::try_trans_any_all_as_exists(
|
|
ObDMLStmt *stmt,
|
|
ObIArray<ObRawExpr* > &exprs,
|
|
ObNotNullContext *not_null_cxt,
|
|
bool is_bool_expr,
|
|
bool &trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_happened = false;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) {
|
|
if (OB_FAIL(try_trans_any_all_as_exists(stmt,
|
|
exprs.at(i),
|
|
not_null_cxt,
|
|
is_bool_expr,
|
|
is_happened))) {
|
|
LOG_WARN("failed to try trans any all as exists", K(ret));
|
|
} else {
|
|
trans_happened |= is_happened;
|
|
}
|
|
}
|
|
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;
|
|
}
|