906 lines
38 KiB
C++
906 lines
38 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_or_expansion.h"
|
|
#include "sql/resolver/dml/ob_dml_stmt.h"
|
|
#include "sql/resolver/expr/ob_raw_expr_util.h"
|
|
#include "sql/rewrite/ob_transform_utils.h"
|
|
#include "sql/rewrite/ob_transformer_impl.h"
|
|
#include "sql/optimizer/ob_optimizer_util.h"
|
|
#include "common/ob_smart_call.h"
|
|
|
|
namespace oceanbase {
|
|
using namespace common;
|
|
namespace sql {
|
|
const int64_t ObTransformOrExpansion::MAX_STMT_NUM_FOR_OR_EXPANSION = 10;
|
|
const int64_t ObTransformOrExpansion::MAX_TIMES_FOR_OR_EXPANSION = 5;
|
|
|
|
int ObTransformOrExpansion::transform_one_stmt(
|
|
ObIArray<ObParentDMLStmt>& parent_stmts, ObDMLStmt*& stmt, bool& trans_happened)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_valid = false;
|
|
bool is_topk = false;
|
|
ObDMLStmt* trans_stmt = NULL;
|
|
ObDMLStmt* upper_stmt = NULL;
|
|
ObSelectStmt* spj_stmt = NULL;
|
|
ObSEArray<ObRawExpr*, 4> generated_exprs;
|
|
ObSEArray<ObRawExpr*, 4> conds;
|
|
ObSEArray<int64_t, 4> expr_pos;
|
|
ObSEArray<int64_t, 4> or_expr_counts;
|
|
trans_happened = false;
|
|
if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->schema_checker_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("stmt is NULL", K(ret));
|
|
} else if (try_times_ >= MAX_TIMES_FOR_OR_EXPANSION) {
|
|
// do nothing
|
|
} else if (OB_FAIL(check_stmt_validity(*stmt, is_valid))) {
|
|
LOG_WARN("failed to check stmt validity", K(ret));
|
|
} else if (!is_valid) {
|
|
// do nothing
|
|
} else if (OB_FAIL(get_trans_view(stmt, upper_stmt, spj_stmt))) {
|
|
LOG_WARN("failed to get spj stmt", K(ret));
|
|
} else {
|
|
is_topk = stmt->has_order_by() && stmt->has_limit();
|
|
if (OB_FAIL(prepare_or_condition(spj_stmt, conds, expr_pos, or_expr_counts, is_topk))) {
|
|
LOG_WARN("failed to prepare or condition", K(ret));
|
|
} else if (conds.count() != or_expr_counts.count() || conds.count() != expr_pos.count()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected or expr counts and conditions", K(ret));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && !trans_happened && i < conds.count(); ++i) {
|
|
ObSelectStmt* transformed_union_stmt = NULL;
|
|
bool can_union_distinct = false;
|
|
bool spj_is_unique = false;
|
|
bool skip_this_cond = false;
|
|
trans_stmt = upper_stmt;
|
|
if (OB_FAIL(preprocess_or_condition(
|
|
spj_stmt, conds.at(i), can_union_distinct, spj_is_unique, skip_this_cond, is_topk))) {
|
|
LOG_WARN("failed to preprocess or condition", K(ret));
|
|
} else if (skip_this_cond) {
|
|
/*do nothing*/
|
|
} else if (OB_FAIL(transform_or_expansion(parent_stmts,
|
|
spj_stmt,
|
|
expr_pos.at(i),
|
|
or_expr_counts.at(i),
|
|
can_union_distinct,
|
|
spj_is_unique,
|
|
transformed_union_stmt))) {
|
|
LOG_WARN("failed to do transformation", K(ret));
|
|
} else if (OB_FAIL(merge_stmt(trans_stmt, spj_stmt, transformed_union_stmt))) {
|
|
LOG_WARN("failed to merge stmt", K(ret));
|
|
} else if (spj_stmt->get_stmt_hint().enable_use_concat()) {
|
|
++try_times_;
|
|
stmt = trans_stmt;
|
|
trans_happened = true;
|
|
cost_based_trans_tried_ = true;
|
|
} else if (OB_FAIL(accept_transform(parent_stmts, stmt, trans_stmt, trans_happened))) {
|
|
LOG_WARN("failed to accept transform", K(ret));
|
|
} else {
|
|
++try_times_;
|
|
}
|
|
if (OB_SUCC(ret) && trans_happened) {
|
|
ctx_->happened_cost_based_trans_ |= OR_EXPANSION;
|
|
LOG_TRACE("has use concat hint, after or expansion", K(*stmt));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::adjust_transform_types(uint64_t& transform_types)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (cost_based_trans_tried_) {
|
|
transform_types &= (~transformer_type_);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::has_odd_function(const ObDMLStmt& stmt, bool& has)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
has = false;
|
|
if (stmt.is_select_stmt()) {
|
|
const ObSelectStmt& select_stmt = static_cast<const ObSelectStmt&>(stmt);
|
|
has = (select_stmt.is_contains_assignment() || NULL != select_stmt.get_select_into() ||
|
|
!select_stmt.get_cte_exprs().empty() || !select_stmt.get_cycle_items().empty() ||
|
|
!select_stmt.get_search_by_items().empty() || select_stmt.has_materalized_view());
|
|
}
|
|
if (OB_SUCC(ret) && !has) {
|
|
ObSEArray<ObSelectStmt*, 4> child_stmts;
|
|
if (OB_FAIL(stmt.get_child_stmts(child_stmts))) {
|
|
LOG_WARN("failed to get child stmt", K(ret));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && !has && i < child_stmts.count(); ++i) {
|
|
if (OB_ISNULL(child_stmts.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("child stmt is null", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(has_odd_function(*child_stmts.at(i), has)))) {
|
|
LOG_WARN("failed to check has odd function", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::check_stmt_validity(ObDMLStmt& stmt, bool& is_valid)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool has_odd_func = false;
|
|
bool contain_inner_table = false;
|
|
bool check_status = true;
|
|
is_valid = false;
|
|
if (stmt.get_stmt_hint().enable_no_expand()) {
|
|
is_valid = false;
|
|
LOG_TRACE("has no expand hint.", K(is_valid));
|
|
} else if (stmt.is_set_stmt() || stmt.get_from_item_size() == 0 || !stmt.is_sel_del_upd()) {
|
|
// do nothing
|
|
} else if (OB_FAIL(stmt.check_if_contain_inner_table(contain_inner_table))) {
|
|
LOG_WARN("failed to check if contain inner table", K(ret));
|
|
} else if (contain_inner_table && !stmt.get_stmt_hint().enable_use_concat()) {
|
|
// do not rewrite a inner table stmt with a cost-based rule
|
|
} else if ((stmt.is_update_stmt() || stmt.is_delete_stmt()) &&
|
|
OB_FAIL(check_upd_del_stmt_validity(static_cast<ObDelUpdStmt*>(&stmt), check_status))) {
|
|
LOG_WARN("failed to check upd del stmt validity", K(ret));
|
|
} else if (!check_status) {
|
|
/*do nothing */
|
|
} else if (stmt.is_select_stmt() &&
|
|
OB_FAIL(check_select_expr_validity(static_cast<ObSelectStmt&>(stmt), check_status))) {
|
|
LOG_WARN("failed to check select expr validity", K(ret));
|
|
} else if (!check_status) {
|
|
/*do nothing */
|
|
} else if (stmt.is_hierarchical_query()) {
|
|
/*do nothing */
|
|
} else if (OB_FAIL(has_odd_function(stmt, has_odd_func))) {
|
|
LOG_WARN("failed to check has odd function", K(ret));
|
|
} else if (has_odd_func) {
|
|
// do nothing
|
|
} else {
|
|
// pre-check conditions
|
|
int64_t or_expr_cnt = 0;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_valid && i < stmt.get_condition_size(); ++i) {
|
|
if (OB_ISNULL(stmt.get_condition_expr(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("condition expr is null", K(ret));
|
|
} else if (OB_FAIL(is_condition_valid(stmt,
|
|
*stmt.get_condition_expr(i),
|
|
or_expr_cnt,
|
|
is_valid,
|
|
stmt.has_order_by() && stmt.has_limit()))) {
|
|
LOG_WARN("failed to check condition validity", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::check_select_expr_validity(ObSelectStmt& stmt, bool& is_valid)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_valid = true;
|
|
ObIArray<SelectItem>& select_items = stmt.get_select_items();
|
|
ObRawExpr* select_expr = NULL;
|
|
for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < select_items.count(); ++i) {
|
|
if (OB_ISNULL(select_expr = select_items.at(i).expr_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null expr", K(ret), K(select_items.at(i)));
|
|
} else if (ObLongTextType == select_expr->get_data_type() || ObLobType == select_expr->get_data_type()) {
|
|
is_valid = false;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::check_upd_del_stmt_validity(ObDelUpdStmt* stmt, bool& is_valid)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_valid = true;
|
|
if (OB_ISNULL(stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("have invalid params", K(ret), K(stmt));
|
|
} else {
|
|
const ObIArray<TableColumns>& table_columns = stmt->get_all_table_columns();
|
|
if (1 != table_columns.count()) {
|
|
is_valid = false;
|
|
} else {
|
|
const ObIArray<ColumnItem>& column_items = stmt->get_column_items();
|
|
ObRawExpr* column_expr = NULL;
|
|
for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < column_items.count(); ++i) {
|
|
if (OB_ISNULL(column_expr = column_items.at(i).expr_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null expr", K(ret), K(column_items.at(i)));
|
|
} else if (ObLongTextType == column_expr->get_data_type() || ObLobType == column_expr->get_data_type()) {
|
|
is_valid = false;
|
|
}
|
|
}
|
|
const ObIArray<IndexDMLInfo>& index_infos = table_columns.at(0).index_dml_infos_;
|
|
for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < index_infos.count(); ++i) {
|
|
if (NULL != stmt->get_part_expr(index_infos.at(i).loc_table_id_, index_infos.at(i).index_tid_)) {
|
|
is_valid = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::get_trans_view(ObDMLStmt* stmt, ObDMLStmt*& upper_stmt, ObSelectStmt*& child_stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObStmtFactory* stmt_factory = NULL;
|
|
ObRawExprFactory* expr_factory = NULL;
|
|
child_stmt = NULL;
|
|
if (OB_ISNULL(ctx_) || OB_ISNULL(stmt) || OB_ISNULL(stmt_factory = ctx_->stmt_factory_) ||
|
|
OB_ISNULL(expr_factory = ctx_->expr_factory_) || OB_UNLIKELY(!stmt->is_sel_del_upd())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN(
|
|
"have invalid params", K(ret), K(ctx_), K(stmt), K(stmt_factory), K(expr_factory), K(stmt->is_sel_del_upd()));
|
|
} else if (stmt->is_select_stmt() && static_cast<ObSelectStmt*>(stmt)->is_spj()) {
|
|
upper_stmt = stmt;
|
|
child_stmt = static_cast<ObSelectStmt*>(stmt);
|
|
} else if (OB_FAIL(ObTransformUtils::deep_copy_stmt(*stmt_factory, *expr_factory, stmt, upper_stmt))) {
|
|
LOG_WARN("failed to deep copy stmt", K(ret));
|
|
} else if (OB_ISNULL(upper_stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected error", K(ret), K(upper_stmt));
|
|
} else if (OB_FAIL(ObTransformUtils::create_simple_view(ctx_, upper_stmt, child_stmt, false))) {
|
|
LOG_WARN("failed to create simple view", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::merge_stmt(ObDMLStmt*& upper_stmt, ObSelectStmt* input_stmt, ObSelectStmt* union_stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(upper_stmt) || OB_ISNULL(union_stmt) || OB_ISNULL(input_stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("params have null", K(ret), K(upper_stmt), K(union_stmt), K(input_stmt));
|
|
} else if (upper_stmt == input_stmt) {
|
|
int64_t origin_select_item_count = input_stmt->get_select_item_size();
|
|
if (origin_select_item_count == union_stmt->get_select_item_size()) {
|
|
upper_stmt = union_stmt;
|
|
} else {
|
|
ObSelectStmt* temp_stmt = NULL;
|
|
if (OB_FAIL(ObTransformUtils::create_stmt_with_generated_table(ctx_, union_stmt, temp_stmt))) {
|
|
LOG_WARN("create stmt with generated_table failed", K(ret));
|
|
} else if (OB_FAIL(remove_stmt_select_item(temp_stmt, origin_select_item_count))) {
|
|
LOG_WARN("just stmt select item failed", K(ret));
|
|
} else {
|
|
upper_stmt = temp_stmt;
|
|
}
|
|
}
|
|
} else if (OB_UNLIKELY(upper_stmt->get_table_size() != 1) || OB_ISNULL(upper_stmt->get_table_item(0))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid upper stmt", K(ret));
|
|
} else {
|
|
upper_stmt->get_table_item(0)->ref_query_ = union_stmt;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::remove_stmt_select_item(ObSelectStmt* select_stmt, int64_t select_item_count)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(select_stmt) || select_item_count < 0 || select_stmt->get_select_item_size() < select_item_count) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid argument", K(select_stmt), K(select_item_count), K(select_stmt->get_select_item_size()), K(ret));
|
|
} else {
|
|
int64_t i_select_item = select_stmt->get_select_item_size();
|
|
do {
|
|
if (OB_FAIL(select_stmt->get_select_items().remove(i_select_item - 1))) {
|
|
LOG_WARN("remove select item failed", K(ret));
|
|
} else {
|
|
--i_select_item;
|
|
}
|
|
} while (OB_SUCC(ret) && i_select_item != select_item_count);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::check_condition_on_same_columns(
|
|
const ObDMLStmt& stmt, const ObRawExpr& expr, bool& using_same_cols)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
using_same_cols = false;
|
|
if (T_OP_OR == expr.get_expr_type()) {
|
|
int64_t table_id = OB_INVALID_ID;
|
|
ColumnBitSet column_bit_set;
|
|
using_same_cols = true;
|
|
for (int64_t i = 0; OB_SUCC(ret) && using_same_cols && i < expr.get_param_count(); ++i) {
|
|
bool from_same_table = true;
|
|
ColumnBitSet tmp;
|
|
if (OB_FAIL(extract_columns(expr.get_param_expr(i), stmt.get_current_level(), table_id, from_same_table, tmp))) {
|
|
LOG_WARN("failed to extract columns info", K(ret));
|
|
} else if (!from_same_table) {
|
|
using_same_cols = false;
|
|
} else if (0 == i) {
|
|
column_bit_set.add_members(tmp);
|
|
using_same_cols = column_bit_set.bit_count() > 0;
|
|
} else if (!column_bit_set.equal(tmp)) {
|
|
using_same_cols = false;
|
|
}
|
|
}
|
|
} else if (T_OP_IN == expr.get_expr_type() && OB_NOT_NULL(expr.get_param_expr(1)) &&
|
|
T_OP_ROW == expr.get_param_expr(1)->get_expr_type()) {
|
|
using_same_cols = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::extract_columns(const ObRawExpr* expr, const int64_t stmt_level, int64_t& table_id,
|
|
bool& from_same_table, ColumnBitSet& col_bit_set)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_stack_overflow = false;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("expr is null");
|
|
} 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 (expr->is_column_ref_expr()) {
|
|
if (expr->get_expr_level() == stmt_level) {
|
|
const ObColumnRefRawExpr* col_expr = static_cast<const ObColumnRefRawExpr*>(expr);
|
|
if (OB_INVALID_ID == table_id) {
|
|
table_id = col_expr->get_table_id();
|
|
}
|
|
if (table_id != col_expr->get_table_id()) {
|
|
from_same_table = false;
|
|
} else if (OB_FAIL(col_bit_set.add_member(col_expr->get_column_id()))) {
|
|
LOG_WARN("failed to add member", K(ret));
|
|
}
|
|
}
|
|
} else if (expr->has_flag(CNT_COLUMN)) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) {
|
|
if (OB_FAIL(SMART_CALL(
|
|
extract_columns(expr->get_param_expr(i), stmt_level, table_id, from_same_table, col_bit_set)))) {
|
|
LOG_WARN("failed to extract columns", K(ret));
|
|
} else if (!from_same_table) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::is_contain_join_cond(const ObDMLStmt& stmt, const ObRawExpr* expr, bool& is_contain)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_contain = false;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect null expr", K(ret));
|
|
} else if (expr->has_flag(IS_JOIN_COND)) {
|
|
bool is_correlated = false;
|
|
if (OB_FAIL(ObTransformUtils::is_correlated_expr(expr, stmt.get_current_level() - 1, is_correlated))) {
|
|
LOG_WARN("failed to check is correlated expr", K(ret));
|
|
} else if (!is_correlated) {
|
|
is_contain = true;
|
|
}
|
|
} else if (T_OP_AND == expr->get_expr_type()) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_contain && i < expr->get_param_count(); ++i) {
|
|
if (OB_FAIL(SMART_CALL(is_contain_join_cond(stmt, expr->get_param_expr(i), is_contain)))) {
|
|
LOG_WARN("failed to check is contain join cond", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::is_match_index(const ObDMLStmt& stmt, const ObRawExpr* expr, bool& is_match)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_match = false;
|
|
if (OB_ISNULL(ctx_) || OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect null ctx", K(ret));
|
|
} else if (expr->has_flag(IS_SIMPLE_COND) || expr->has_flag(IS_RANGE_COND)) {
|
|
ObSEArray<ObRawExpr*, 2> column_exprs;
|
|
ObColumnRefRawExpr* col_expr = NULL;
|
|
if (OB_FAIL(ObRawExprUtils::extract_column_exprs(expr, column_exprs))) {
|
|
LOG_WARN("failed to extrace column exprs", K(ret));
|
|
} else if (1 != column_exprs.count()) {
|
|
// do nothing
|
|
} else if (OB_ISNULL(column_exprs.at(0))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect null expr", K(ret));
|
|
} else if (!column_exprs.at(0)->is_column_ref_expr()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("expect column ref expr", K(*column_exprs.at(0)), K(ret));
|
|
} else if (OB_FALSE_IT(col_expr = static_cast<ObColumnRefRawExpr*>(column_exprs.at(0)))) {
|
|
} else if (OB_ISNULL(stmt.get_table_item_by_id(col_expr->get_table_id()))) {
|
|
// do nothing
|
|
} else if (OB_FAIL(ObTransformUtils::is_match_index(
|
|
ctx_->sql_schema_guard_, &stmt, col_expr, is_match, &ctx_->equal_sets_))) {
|
|
LOG_WARN("failed to check is match index", K(ret));
|
|
}
|
|
} else if (T_OP_IN == expr->get_expr_type()) {
|
|
const ObRawExpr* right_expr = NULL;
|
|
if (OB_UNLIKELY(2 != expr->get_param_count())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("in expr should have 2 param", K(expr->get_param_count()), K(ret));
|
|
} else if (OB_ISNULL(right_expr = expr->get_param_expr(1))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("null expr", K(ret));
|
|
} else if (T_OP_ROW == right_expr->get_expr_type()) {
|
|
bool is_const = true;
|
|
for (int64_t i = 0; OB_SUCC(ret) && is_const && i < right_expr->get_param_count(); i++) {
|
|
const ObRawExpr* temp_expr = right_expr->get_param_expr(i);
|
|
if (OB_ISNULL(temp_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("null expr", K(ret));
|
|
} else if (!temp_expr->is_const_expr()) {
|
|
is_const = false;
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
const ObColumnRefRawExpr* col_expr = NULL;
|
|
if (OB_FAIL(ret) || !is_const) {
|
|
// do nothing
|
|
} else if (OB_ISNULL(expr->get_param_expr(0))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect null expr", K(ret));
|
|
} else if (!expr->get_param_expr(0)->is_column_ref_expr()) {
|
|
// do nothing
|
|
} else if (OB_FALSE_IT(col_expr = static_cast<const ObColumnRefRawExpr*>(expr->get_param_expr(0)))) {
|
|
} else if (OB_ISNULL(stmt.get_table_item_by_id(col_expr->get_table_id()))) {
|
|
// do nothing
|
|
} else if (OB_FAIL(ObTransformUtils::is_match_index(
|
|
ctx_->sql_schema_guard_, &stmt, col_expr, is_match, &ctx_->equal_sets_))) {
|
|
LOG_WARN("failed to check is match index", K(ret));
|
|
}
|
|
} else { /*do nothing*/
|
|
}
|
|
} else if (T_OP_AND == expr->get_expr_type()) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_match && i < expr->get_param_count(); ++i) {
|
|
if (OB_FAIL(SMART_CALL(is_match_index(stmt, expr->get_param_expr(i), is_match)))) {
|
|
LOG_WARN("failed to check is match index", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::is_simple_cond(const ObDMLStmt& stmt, const ObRawExpr* expr, bool& is_simple)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_simple = false;
|
|
if (OB_ISNULL(expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect null expr", K(ret));
|
|
} else if (1 >= expr->get_relation_ids().num_members()) {
|
|
is_simple = true;
|
|
} else if (T_OP_AND == expr->get_expr_type()) {
|
|
int64_t N = expr->get_param_count();
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_simple && i < N; ++i) {
|
|
if (OB_FAIL(SMART_CALL(is_simple_cond(stmt, expr->get_param_expr(i), is_simple)))) {
|
|
LOG_WARN("failed to check is simple cond", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::is_condition_valid(
|
|
const ObDMLStmt& stmt, const ObRawExpr& expr, int64_t& or_expr_count, bool& is_valid, const bool is_topk)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_valid = false;
|
|
or_expr_count = 0;
|
|
bool using_same_col = false;
|
|
if (expr.has_flag(CNT_ROWNUM)) {
|
|
// do nothing
|
|
} else if (T_OP_OR != expr.get_expr_type() && T_OP_IN != expr.get_expr_type()) {
|
|
// do nothing
|
|
} else if (!is_topk && OB_FAIL(check_condition_on_same_columns(stmt, expr, using_same_col))) {
|
|
LOG_WARN("failed to check condition on same colums", K(ret));
|
|
} else if (!using_same_col || is_topk || expr.has_flag(CNT_SUB_QUERY)) {
|
|
/**
|
|
* Given an order-by + limit query,
|
|
* it possible to push limit down to down by after the query is expanded
|
|
* select * from t where a = 1 or a = 2 order by b limit 10;
|
|
* =>
|
|
* (select * from t where a = 1 order by b limit 10)
|
|
* union all
|
|
* (select * from t where a = 2 and lnnvl(a=1) order by b limit 10)
|
|
* order by b limit 10;
|
|
*
|
|
* when there is an index (a, b), then we can make use of the index order
|
|
* */
|
|
if (T_OP_OR == expr.get_expr_type() && expr.get_param_count() <= MAX_STMT_NUM_FOR_OR_EXPANSION) {
|
|
bool is_all_simple_cond = true;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_valid && i < expr.get_param_count(); i++) {
|
|
const ObRawExpr* temp_expr = expr.get_param_expr(i);
|
|
bool is_contain = false;
|
|
bool is_match = false;
|
|
bool is_simple = false;
|
|
if (OB_ISNULL(temp_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("null expr", K(ret));
|
|
} else if (temp_expr->has_flag(CNT_SUB_QUERY)) {
|
|
is_valid = true;
|
|
} else if (OB_FAIL(is_contain_join_cond(stmt, temp_expr, is_contain))) {
|
|
LOG_WARN("failed to check contain join cond", K(ret));
|
|
} else if (is_contain) {
|
|
is_valid = true;
|
|
} else if (OB_FAIL(is_match_index(stmt, temp_expr, is_match))) {
|
|
LOG_WARN("failed to check is match index", K(ret));
|
|
} else if (is_match) {
|
|
is_valid = true;
|
|
} else if (OB_FAIL(is_simple_cond(stmt, temp_expr, is_simple))) {
|
|
LOG_WARN("failed to check is simple cond", K(ret));
|
|
} else if (!is_simple) {
|
|
is_all_simple_cond = false;
|
|
}
|
|
}
|
|
if (is_all_simple_cond && !is_valid) {
|
|
if (expr.get_relation_ids().num_members() > 1) {
|
|
is_valid = true;
|
|
}
|
|
}
|
|
if (is_valid || stmt.get_stmt_hint().enable_use_concat()) {
|
|
or_expr_count = expr.get_param_count();
|
|
is_valid = true;
|
|
}
|
|
} else if (T_OP_IN == expr.get_expr_type() && !expr.has_flag(CNT_SUB_QUERY)) {
|
|
const ObRawExpr* right_expr = NULL;
|
|
if (OB_UNLIKELY(2 != expr.get_param_count())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("in expr should have 2 param", K(expr.get_param_count()), K(ret));
|
|
} else if (OB_ISNULL(right_expr = expr.get_param_expr(1))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("null expr", K(ret));
|
|
} else if (T_OP_ROW == right_expr->get_expr_type() &&
|
|
right_expr->get_param_count() <= MAX_STMT_NUM_FOR_OR_EXPANSION) {
|
|
or_expr_count = right_expr->get_param_count();
|
|
is_valid = true;
|
|
for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < right_expr->get_param_count(); i++) {
|
|
const ObRawExpr* temp_expr = right_expr->get_param_expr(i);
|
|
if (OB_ISNULL(temp_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("null expr", K(ret));
|
|
} else if (!temp_expr->has_flag(IS_CONST)) {
|
|
or_expr_count = 0;
|
|
is_valid = false;
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
} else { /*do nothing*/
|
|
}
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
LOG_TRACE("finish to check transform validity", K(expr.get_expr_type()), K(is_valid), K(ret));
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::transform_or_expansion(common::ObIArray<ObParentDMLStmt>& parent_stmts, ObDMLStmt* stmt,
|
|
const int64_t transformed_expr_pos, const int64_t or_expr_count, bool can_union_distinct, bool spj_is_unique,
|
|
ObSelectStmt*& transformed_stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
UNUSED(parent_stmts);
|
|
ObStmtFactory* stmt_factory = NULL;
|
|
ObRawExprFactory* expr_factory = NULL;
|
|
ObSQLSessionInfo* session_info = NULL;
|
|
if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(session_info = ctx_->session_info_) ||
|
|
OB_ISNULL(stmt_factory = ctx_->stmt_factory_) || OB_ISNULL(expr_factory = ctx_->expr_factory_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(stmt), K(ctx_), K(session_info), K(stmt_factory), K(expr_factory), K(ret));
|
|
} else if (OB_UNLIKELY(or_expr_count <= 0)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("or expr should large than 0", K(or_expr_count), K(ret));
|
|
} else if (stmt->is_select_stmt()) {
|
|
ObSelectStmt* input_stmt = static_cast<ObSelectStmt*>(stmt);
|
|
ObSEArray<ObSelectStmt*, 2> child_stmts;
|
|
ObSelectStmt* union_stmt = NULL;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < or_expr_count; i++) {
|
|
ObSelectStmt* child_stmt = NULL;
|
|
if (OB_FAIL(stmt_factory->create_stmt(child_stmt)) || OB_ISNULL(child_stmt)) {
|
|
LOG_WARN("failed to create stmt factory", K(child_stmt), K(ret));
|
|
} else if (OB_FAIL(child_stmt->deep_copy(*stmt_factory, *expr_factory, *input_stmt))) {
|
|
LOG_WARN("failed to deep copy child statement", K(ret));
|
|
} else if (OB_FAIL(child_stmt->update_stmt_table_id(*input_stmt))) {
|
|
LOG_WARN("failed to update table id", K(ret));
|
|
} else if (OB_FAIL(adjust_or_expansion_stmt(transformed_expr_pos, i, can_union_distinct, child_stmt))) {
|
|
LOG_WARN("failed to adjust children stmt", K(ret));
|
|
} else if (can_union_distinct && !spj_is_unique &&
|
|
OB_FAIL(ObTransformUtils::recursive_set_stmt_unique(child_stmt, ctx_, true))) {
|
|
LOG_WARN("failed to set stmt unique", K(ret));
|
|
} else if (OB_FAIL(child_stmts.push_back(child_stmt))) {
|
|
LOG_WARN("failed to push back stmt", K(ret));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(ObTransformUtils::create_union_stmt(ctx_, can_union_distinct, child_stmts, union_stmt))) {
|
|
LOG_WARN("failed to create union stmt", K(union_stmt), K(ret));
|
|
} else if (OB_ISNULL(union_stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected null", K(ret), K(union_stmt));
|
|
} else if (OB_FAIL(union_stmt->formalize_stmt(session_info))) {
|
|
LOG_WARN("failed to formalize stmt", K(ret));
|
|
} else {
|
|
transformed_stmt = union_stmt;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::adjust_or_expansion_stmt(const int64_t transformed_expr_pos, const int64_t param_pos,
|
|
bool can_union_distinct, ObSelectStmt*& or_expansion_stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo* session_info = NULL;
|
|
ObRawExprFactory* expr_factory = NULL;
|
|
ObRawExpr* transformed_expr = NULL;
|
|
ObSEArray<ObQueryRefRawExpr*, 4> removed_subqueries;
|
|
ObSEArray<ObQueryRefRawExpr*, 4> need_add_subqueries;
|
|
if (OB_ISNULL(ctx_) || OB_ISNULL(session_info = ctx_->session_info_) ||
|
|
OB_ISNULL(expr_factory = ctx_->expr_factory_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("null point error", K(ctx_), K(session_info), K(expr_factory), K(ret));
|
|
} else if (OB_ISNULL(or_expansion_stmt)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("null stmt", K(ret));
|
|
} else if (OB_UNLIKELY(transformed_expr_pos < 0) ||
|
|
OB_UNLIKELY(transformed_expr_pos >= or_expansion_stmt->get_condition_exprs().count())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid condition expr pos",
|
|
K(transformed_expr_pos),
|
|
K(or_expansion_stmt->get_condition_exprs().count()),
|
|
K(ret));
|
|
} else if (OB_ISNULL(transformed_expr = or_expansion_stmt->get_condition_exprs().at(transformed_expr_pos))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("null transformed expr", K(ret));
|
|
} else if (OB_FAIL(or_expansion_stmt->get_condition_exprs().remove(transformed_expr_pos))) {
|
|
LOG_WARN("failed to remove condition expr", K(ret));
|
|
} else if (transformed_expr->has_flag(CNT_SUB_QUERY) &&
|
|
OB_FAIL(ObTransformUtils::extract_query_ref_expr(transformed_expr, removed_subqueries))) {
|
|
LOG_WARN("failed to extract query ref expr", K(ret));
|
|
} else if (OB_FAIL(ObOptimizerUtil::remove_item(or_expansion_stmt->get_subquery_exprs(), removed_subqueries))) {
|
|
LOG_WARN("failed to remove subquery exprs", K(ret));
|
|
} else if (T_OP_OR == transformed_expr->get_expr_type()) {
|
|
ObSEArray<ObRawExpr*, 4> generated_exprs;
|
|
if (OB_FAIL(create_expr_for_or_expr(
|
|
*transformed_expr, param_pos, can_union_distinct, generated_exprs, need_add_subqueries))) {
|
|
LOG_WARN("failed to create expr", K(ret));
|
|
} else if (OB_FAIL(append(or_expansion_stmt->get_condition_exprs(), generated_exprs))) {
|
|
LOG_WARN("failed to append expr", K(ret));
|
|
} else if (OB_FAIL(append(or_expansion_stmt->get_subquery_exprs(), need_add_subqueries))) {
|
|
LOG_WARN("failed to append expr", K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
} else if (T_OP_IN == transformed_expr->get_expr_type()) {
|
|
ObSEArray<ObRawExpr*, 4> generated_exprs;
|
|
if (OB_FAIL(create_expr_for_in_expr(
|
|
*transformed_expr, param_pos, can_union_distinct, generated_exprs, need_add_subqueries))) {
|
|
LOG_WARN("failed to create expr", K(ret), K(generated_exprs));
|
|
} else if (OB_FAIL(append(or_expansion_stmt->get_condition_exprs(), generated_exprs))) {
|
|
LOG_WARN("failed to append exprs", K(ret));
|
|
} else if (OB_FAIL(append(or_expansion_stmt->get_subquery_exprs(), need_add_subqueries))) {
|
|
LOG_WARN("failed to append expr", K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected expr type", K(transformed_expr->get_expr_type()), K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(or_expansion_stmt->formalize_stmt(session_info))) {
|
|
LOG_WARN("failed to formalize stmt", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::create_expr_for_in_expr(const ObRawExpr& transformed_expr, const int64_t param_pos,
|
|
bool can_union_distinct, ObIArray<ObRawExpr*>& generated_exprs, ObIArray<ObQueryRefRawExpr*>& subqueries)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObRawExpr* left_expr = NULL;
|
|
const ObRawExpr* right_expr = NULL;
|
|
ObRawExpr* temp_expr = NULL;
|
|
ObRawExprFactory* expr_factory = NULL;
|
|
ObSQLSessionInfo* session_info = NULL;
|
|
if (OB_ISNULL(ctx_) || OB_ISNULL(expr_factory = ctx_->expr_factory_) ||
|
|
OB_ISNULL(session_info = ctx_->session_info_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ctx_), K(session_info), K(expr_factory), K(ret));
|
|
} else if (OB_UNLIKELY(T_OP_IN != transformed_expr.get_expr_type())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected expr type", K(transformed_expr.get_expr_type()), K(ret));
|
|
} else if (OB_UNLIKELY(2 != transformed_expr.get_param_count())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("in expr should have 2 param", K(transformed_expr.get_param_count()), K(ret));
|
|
} else if (OB_ISNULL(left_expr = transformed_expr.get_param_expr(0)) ||
|
|
OB_ISNULL(right_expr = transformed_expr.get_param_expr(1))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("null expr", K(left_expr), K(right_expr), K(ret));
|
|
} else if (T_OP_ROW != right_expr->get_expr_type()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected type", K(right_expr->get_expr_type()), K(ret));
|
|
} else if (OB_UNLIKELY(param_pos < 0) || OB_UNLIKELY(param_pos >= right_expr->get_param_count())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected expr pos", K(param_pos), K(right_expr->get_param_count()), K(ret));
|
|
} else if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(const_cast<ObRawExpr*>(left_expr), subqueries))) {
|
|
LOG_WARN("failed to extract query ref expr", K(ret));
|
|
}
|
|
for (int64_t i = can_union_distinct ? param_pos : 0; OB_SUCC(ret) && i <= param_pos; ++i) {
|
|
if (OB_FAIL(ObRawExprUtils::create_equal_expr(
|
|
*expr_factory, session_info, left_expr, right_expr->get_param_expr(i), temp_expr))) {
|
|
LOG_WARN("failed to create double op expr", K(ret));
|
|
} else if (i == param_pos) {
|
|
// do nothing
|
|
} else if (OB_FAIL(ObRawExprUtils::build_lnnvl_expr(*expr_factory, temp_expr, temp_expr))) {
|
|
LOG_WARN("failed to build lnnvl expr", K(ret));
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(generated_exprs.push_back(temp_expr))) {
|
|
LOG_WARN("failed to push back temp expr", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObTransformOrExpansion::create_expr_for_or_expr(ObRawExpr& transformed_expr, const int64_t param_pos,
|
|
bool can_union_distinct, common::ObIArray<ObRawExpr*>& generated_exprs, ObIArray<ObQueryRefRawExpr*>& subqueries)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObRawExprFactory* expr_factory = NULL;
|
|
if (OB_ISNULL(ctx_) || OB_ISNULL(expr_factory = ctx_->expr_factory_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("null point error", K(ctx_), K(expr_factory), K(ret));
|
|
} else if (OB_UNLIKELY(T_OP_OR != transformed_expr.get_expr_type())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected expr type", K(transformed_expr.get_expr_type()), K(ret));
|
|
} else if (OB_UNLIKELY(param_pos < 0) || OB_UNLIKELY(param_pos >= transformed_expr.get_param_count())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected expr pos", K(param_pos), K(transformed_expr.get_param_count()), K(ret));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i <= param_pos; i++) {
|
|
ObRawExpr* expr = NULL;
|
|
ObRawExpr* temp_expr = NULL;
|
|
if (OB_ISNULL(expr = transformed_expr.get_param_expr(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("null expr", K(ret));
|
|
} else if (i == param_pos) {
|
|
temp_expr = expr;
|
|
if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(expr, subqueries))) {
|
|
LOG_WARN("failed to extract query ref expr", K(ret));
|
|
} else if (OB_FAIL(ObTransformUtils::flatten_expr(temp_expr, generated_exprs))) {
|
|
LOG_WARN("failed to flatten expr", K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
} else if (can_union_distinct) {
|
|
/*do nothing */
|
|
} else if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(expr, subqueries))) {
|
|
LOG_WARN("failed to extract query ref expr", K(ret));
|
|
} else if (OB_FAIL(ObRawExprUtils::build_lnnvl_expr(*expr_factory, expr, temp_expr))) {
|
|
LOG_WARN("failed to create lnnvl expr", K(ret));
|
|
} else if (OB_FAIL(generated_exprs.push_back(temp_expr))) {
|
|
LOG_WARN("failed to push back expr", K(ret));
|
|
} else { /*do nothing*/
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief ObTransformOrExpansion::prepare_or_condition
|
|
* prepare or expansion condition,find out conditions which can be expanded and record or expr counts.
|
|
* conditions contain sub query placed at head of output arrays, transform first.
|
|
*/
|
|
int ObTransformOrExpansion::prepare_or_condition(ObSelectStmt* stmt, common::ObIArray<ObRawExpr*>& conds,
|
|
common::ObIArray<int64_t>& expr_pos, common::ObIArray<int64_t>& or_expr_counts, const bool is_topk)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_valid = false;
|
|
ObSEArray<ObRawExpr*, 4> temp_conds;
|
|
ObSEArray<int64_t, 4> temp_expr_pos;
|
|
ObSEArray<int64_t, 4> temp_or_expr_counts;
|
|
ObRawExpr* cond = NULL;
|
|
int64_t or_expr_count = 0;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_condition_size(); ++i) {
|
|
if (OB_ISNULL(cond = stmt->get_condition_expr(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("stmt condition is null", K(ret));
|
|
} else if (OB_FAIL(is_condition_valid(*stmt, *cond, or_expr_count, is_valid, is_topk))) {
|
|
LOG_WARN("failed to check condition is valid", K(ret));
|
|
} else if (is_valid && cond->has_flag(CNT_SUB_QUERY)) {
|
|
if (OB_FAIL(conds.push_back(cond))) {
|
|
LOG_WARN("failed to push back conds", K(ret));
|
|
} else if (OB_FAIL(expr_pos.push_back(i))) {
|
|
LOG_WARN("failed to push back expr pos", K(ret));
|
|
} else if (OB_FAIL(or_expr_counts.push_back(or_expr_count))) {
|
|
LOG_WARN("failed to push back or expr counts", K(ret));
|
|
}
|
|
} else if (is_valid) {
|
|
if (OB_FAIL(temp_conds.push_back(cond))) {
|
|
LOG_WARN("failed to push back temp conds", K(ret));
|
|
} else if (OB_FAIL(temp_expr_pos.push_back(i))) {
|
|
LOG_WARN("failed to push back temp expr pos", K(ret));
|
|
} else if (OB_FAIL(temp_or_expr_counts.push_back(or_expr_count))) {
|
|
LOG_WARN("failed to push back temp or expr counts", K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(append(conds, temp_conds))) {
|
|
LOG_WARN("failed to append conditions", K(ret));
|
|
} else if (OB_FAIL(append(expr_pos, temp_expr_pos))) {
|
|
LOG_WARN("failed to append expr pos", K(ret));
|
|
} else if (OB_FAIL(append(or_expr_counts, temp_or_expr_counts))) {
|
|
LOG_WARN("failed to append or expr counts", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief ObTransformOrExpansion::preprocess_or_condition
|
|
* move params with subquery to the tail of the expr, and judge can do union distinct
|
|
*/
|
|
int ObTransformOrExpansion::preprocess_or_condition(ObSelectStmt* select_stmt, ObRawExpr* expr,
|
|
bool& can_union_distinct, bool& spj_is_unique, bool& skip_this_cond, const bool is_topk)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t tail = 0;
|
|
int num_sub = 0;
|
|
bool using_same_col = false;
|
|
can_union_distinct = false;
|
|
spj_is_unique = false;
|
|
skip_this_cond = false;
|
|
if (OB_ISNULL(expr) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->schema_checker_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid argument", K(expr), K(ctx_), K(ret));
|
|
} else if (OB_FAIL(check_condition_on_same_columns(*select_stmt, *expr, using_same_col))) {
|
|
LOG_WARN("failed to check condition on same colums", K(ret));
|
|
} else if (T_OP_OR == expr->get_expr_type()) {
|
|
tail = expr->get_param_count() - 1;
|
|
for (int64_t i = expr->get_param_count() - 1; OB_SUCC(ret) && i >= 0; --i) {
|
|
ObRawExpr* param = NULL;
|
|
if (OB_ISNULL(param = expr->get_param_expr(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("param expr is null", K(ret));
|
|
} else if (param->has_flag(CNT_SUB_QUERY)) {
|
|
expr->get_param_expr(i) = expr->get_param_expr(tail);
|
|
expr->get_param_expr(tail--) = param;
|
|
++num_sub;
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && ((is_topk && using_same_col) || num_sub >= 2)) {
|
|
if (OB_FAIL(ObTransformUtils::check_can_set_stmt_unique(select_stmt, can_union_distinct))) {
|
|
LOG_WARN("failed to check can set stmt unique", K(ret));
|
|
} else if (can_union_distinct &&
|
|
OB_FAIL(ObTransformUtils::check_stmt_unique(
|
|
select_stmt, ctx_->session_info_, ctx_->schema_checker_, true /* strict */, spj_is_unique))) {
|
|
LOG_WARN("failed to check stmt unique", K(ret));
|
|
} else { /*do nothing */
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && is_topk && using_same_col && !can_union_distinct) {
|
|
skip_this_cond = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
} /* namespace sql */
|
|
} /* namespace oceanbase */
|