Files
oceanbase/src/sql/rewrite/ob_transform_simplify_subquery.cpp
2024-02-06 21:25:14 +00:00

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(),
&not_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(),
&not_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_,
&not_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(),
&not_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;
}