1470 lines
68 KiB
C++
1470 lines
68 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 "ob_stmt_comparer.h"
|
|
#include "ob_transform_utils.h"
|
|
#include "sql/optimizer/ob_optimizer_util.h"
|
|
#include "sql/ob_sql_context.h"
|
|
#include "common/ob_smart_call.h"
|
|
|
|
|
|
using namespace oceanbase::sql;
|
|
|
|
void ObStmtMapInfo::reset()
|
|
{
|
|
table_map_.reset();
|
|
is_table_equal_ = false;
|
|
from_map_.reset();
|
|
is_from_equal_ = false;
|
|
semi_info_map_.reset();
|
|
is_semi_info_equal_ = false;
|
|
cond_map_.reset();
|
|
is_cond_equal_ = false;
|
|
group_map_.reset();
|
|
is_group_equal_ = false;
|
|
having_map_.reset();
|
|
is_having_equal_ = false;
|
|
is_order_equal_ = false;
|
|
select_item_map_.reset();
|
|
is_select_item_equal_ = false;
|
|
is_distinct_equal_ = false;
|
|
is_qualify_filter_equal_ = false;
|
|
equal_param_map_.reset();
|
|
view_select_item_map_.reset();
|
|
}
|
|
|
|
int ObStmtMapInfo::assign(const ObStmtMapInfo& other)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(table_map_.assign(other.table_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else if (OB_FAIL(from_map_.assign(other.from_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else if (OB_FAIL(semi_info_map_.assign(other.semi_info_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else if (OB_FAIL(cond_map_.assign(other.cond_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else if (OB_FAIL(group_map_.assign(other.group_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else if (OB_FAIL(having_map_.assign(other.having_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else if (OB_FAIL(select_item_map_.assign(other.select_item_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else if (OB_FAIL(equal_param_map_.assign(other.equal_param_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else if (OB_FAIL(view_select_item_map_.assign(other.view_select_item_map_))) {
|
|
LOG_WARN("failed to assign table map", K(ret));
|
|
} else {
|
|
is_table_equal_ = other.is_table_equal_;
|
|
is_from_equal_ = other.is_from_equal_;
|
|
is_semi_info_equal_ = other.is_semi_info_equal_;
|
|
is_cond_equal_ = other.is_cond_equal_;
|
|
is_group_equal_ = other.is_group_equal_;
|
|
is_having_equal_ = other.is_having_equal_;
|
|
is_order_equal_ = other.is_order_equal_;
|
|
is_select_item_equal_ = other.is_select_item_equal_;
|
|
is_distinct_equal_ = other.is_distinct_equal_;
|
|
is_qualify_filter_equal_ = other.is_qualify_filter_equal_;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int StmtCompareHelper::alloc_compare_helper(ObIAllocator &allocator, StmtCompareHelper* &helper)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
void *buf = NULL;
|
|
if (NULL == (buf = allocator.alloc(sizeof(StmtCompareHelper)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("allocate memory failed", K(ret));
|
|
} else {
|
|
helper = new(buf)StmtCompareHelper();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObStmtCompareContext::init(const ObIArray<ObHiddenColumnItem> *calculable_items)
|
|
{
|
|
calculable_items_ = calculable_items;
|
|
}
|
|
|
|
void ObStmtCompareContext::init(const ObDMLStmt *inner,
|
|
const ObDMLStmt *outer,
|
|
const ObStmtMapInfo &map_info,
|
|
const ObIArray<ObHiddenColumnItem> *calculable_items)
|
|
{
|
|
inner_ = inner;
|
|
outer_ = outer;
|
|
map_info_ = map_info;
|
|
calculable_items_ = calculable_items;
|
|
}
|
|
|
|
int ObStmtCompareContext::get_table_map_idx(uint64_t l_table_id, uint64_t r_table_id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t ret_idx = OB_INVALID_ID;
|
|
if (OB_ISNULL(inner_) || OB_ISNULL(outer_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
}
|
|
TableItem *inner_table = NULL;
|
|
TableItem *outer_table = NULL;
|
|
for (int64_t inner_idx = 0; OB_SUCC(ret) && ret_idx == OB_INVALID_ID
|
|
&& inner_idx < map_info_.table_map_.count(); ++inner_idx) {
|
|
int64_t outer_idx = map_info_.table_map_.at(inner_idx);
|
|
if (outer_idx < 0 || outer_idx >= outer_->get_table_size()
|
|
|| inner_idx >= inner_->get_table_size()) {
|
|
// do nothing
|
|
} else if (OB_ISNULL(inner_table = inner_->get_table_items().at(inner_idx)) ||
|
|
OB_ISNULL(outer_table = outer_->get_table_items().at(outer_idx))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("table items are null", K(ret));
|
|
} else if ((inner_table->table_id_ == l_table_id && outer_table->table_id_ == r_table_id) ||
|
|
(inner_table->table_id_ == r_table_id && outer_table->table_id_ == l_table_id)) {
|
|
ret_idx = inner_idx;
|
|
}
|
|
}
|
|
return ret_idx;
|
|
}
|
|
|
|
bool ObStmtCompareContext::compare_column(const ObColumnRefRawExpr &inner,
|
|
const ObColumnRefRawExpr &outer)
|
|
{
|
|
bool bret = false;
|
|
int idx = get_table_map_idx(inner.get_table_id(), outer.get_table_id());
|
|
if (inner.get_table_id() == outer.get_table_id()) {
|
|
bret = inner.get_column_id() == outer.get_column_id();
|
|
} else if (idx == OB_INVALID_ID) {
|
|
//do nothing
|
|
} else if (idx >= map_info_.view_select_item_map_.count()) {
|
|
//do nothing
|
|
} else if (OB_ISNULL(inner_)) {
|
|
} else if (!inner_->get_table_item_by_id(inner.get_table_id())->is_generated_table()) {
|
|
bret = inner.get_column_id() == outer.get_column_id();
|
|
} else {
|
|
int64_t inner_pos = inner.get_column_id() - OB_APP_MIN_COLUMN_ID;
|
|
int64_t outer_pos = outer.get_column_id() - OB_APP_MIN_COLUMN_ID;
|
|
const ObIArray<int64_t> &select_item_map = map_info_.view_select_item_map_.at(idx);
|
|
if (OB_UNLIKELY(inner_pos < 0 || inner_pos >= select_item_map.count()) ||
|
|
OB_INVALID_ID == select_item_map.at(inner_pos)) {
|
|
//do nothing
|
|
} else {
|
|
bret = select_item_map.at(inner_pos) == outer_pos;
|
|
}
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
bool ObStmtCompareContext::compare_const(const ObConstRawExpr &left, const ObConstRawExpr &right)
|
|
{
|
|
int &ret = err_code_;
|
|
bool bret = false;
|
|
if (OB_SUCC(ret) && left.get_result_type() == right.get_result_type()) {
|
|
if (&left == &right) {
|
|
bret = true;
|
|
} else if (left.is_param_expr() && right.is_param_expr()) {
|
|
bool is_left_calc_item = false;
|
|
bool is_right_calc_item = false;
|
|
if (OB_FAIL(is_pre_calc_item(left, is_left_calc_item))) {
|
|
LOG_WARN("failed to is pre calc item", K(ret));
|
|
} else if (OB_FAIL(is_pre_calc_item(right, is_right_calc_item))) {
|
|
LOG_WARN("failed to is pre calc item", K(ret));
|
|
} else if (is_left_calc_item && is_right_calc_item) {
|
|
const ObRawExpr *left_param = NULL;
|
|
const ObRawExpr *right_param = NULL;
|
|
if (OB_FAIL(get_calc_expr(left.get_value().get_unknown(), left_param))) {
|
|
LOG_WARN("faield to get calculable expr", K(ret));
|
|
} else if (OB_FAIL(get_calc_expr(right.get_value().get_unknown(), right_param))) {
|
|
LOG_WARN("failed to get calculable expr", K(ret));
|
|
} else if (OB_ISNULL(left_param) || OB_ISNULL(right_param)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("param exprs are null", K(ret), K(left_param), K(right_param));
|
|
} else {
|
|
bret = left_param->same_as(*right_param, this);
|
|
}
|
|
} else if (is_left_calc_item || is_right_calc_item) {
|
|
bret = false;
|
|
} else if (ignore_param_) {
|
|
bret = ObExprEqualCheckContext::compare_const(left, right);
|
|
} else if (left.get_result_type().get_param().is_equal(
|
|
right.get_result_type().get_param(), CS_TYPE_BINARY)) {
|
|
ObPCParamEqualInfo info;
|
|
info.first_param_idx_ = left.get_value().get_unknown();
|
|
info.second_param_idx_ = right.get_value().get_unknown();
|
|
bret = true;
|
|
if (info.first_param_idx_ != info.second_param_idx_ &&
|
|
OB_FAIL(equal_param_info_.push_back(info))) {
|
|
LOG_WARN("failed to push back equal param info", K(ret));
|
|
}
|
|
}
|
|
} else if (left.is_param_expr() || right.is_param_expr()) {
|
|
bret = ObExprEqualCheckContext::compare_const(left, right);
|
|
} else {
|
|
bret = left.get_value().is_equal(right.get_value(), CS_TYPE_BINARY);
|
|
}
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
int ObStmtCompareContext::is_pre_calc_item(const ObConstRawExpr &const_expr, bool &is_calc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t calc_count = 0;
|
|
is_calc = false;
|
|
if (OB_ISNULL(calculable_items_) || OB_UNLIKELY((calc_count = calculable_items_->count()) < 0
|
|
|| const_expr.get_expr_type() != T_QUESTIONMARK)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected error", K(ret), K(calculable_items_), K(const_expr.get_expr_type()),
|
|
K(calc_count));
|
|
} else if (const_expr.has_flag(IS_DYNAMIC_PARAM)) {
|
|
is_calc = true;
|
|
} else if (calc_count > 0) {
|
|
int64_t q_idx = const_expr.get_value().get_unknown();
|
|
int64_t min_calc_index = calculable_items_->at(0).hidden_idx_;
|
|
if (OB_UNLIKELY(q_idx < 0 || min_calc_index < 0)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get invalid argument", K(q_idx), K(min_calc_index));
|
|
} else if (q_idx - min_calc_index >= 0 && q_idx - min_calc_index < calc_count) {
|
|
is_calc = true;
|
|
} else {/*do nothing*/}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObStmtCompareContext::compare_query(const ObQueryRefRawExpr &first,
|
|
const ObQueryRefRawExpr &second)
|
|
{
|
|
bool bret = false;
|
|
int ret = OB_SUCCESS;
|
|
ObStmtMapInfo stmt_map_info;
|
|
QueryRelation relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
const ObSelectStmt *first_sel = NULL;
|
|
const ObSelectStmt *second_sel = NULL;
|
|
if (&first == &second) {
|
|
bret = true;
|
|
} else if (first.is_set() != second.is_set() || first.is_multiset() != second.is_multiset() ||
|
|
OB_ISNULL(first_sel = first.get_ref_stmt()) ||
|
|
OB_ISNULL(second_sel = second.get_ref_stmt())) {
|
|
bret = false;
|
|
} else if (OB_FAIL(ObStmtComparer::check_stmt_containment(first_sel,
|
|
second_sel,
|
|
stmt_map_info,
|
|
relation,
|
|
true))) {
|
|
LOG_WARN("failed to compute stmt relationship", K(ret));
|
|
err_code_ = ret;
|
|
} else if (stmt_map_info.is_select_item_equal_ && QueryRelation::QUERY_EQUAL == relation) {
|
|
bret = true;
|
|
if (OB_FAIL(append(equal_param_info_, stmt_map_info.equal_param_map_))) {
|
|
LOG_WARN("failed to append equal param", K(ret));
|
|
err_code_ = ret;
|
|
}
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
int ObStmtCompareContext::get_calc_expr(const int64_t param_idx, const ObRawExpr *&expr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(calculable_items_) || calculable_items_->count() <= 0) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("query context is null", K(ret));
|
|
} else {
|
|
int64_t offset = param_idx - calculable_items_->at(0).hidden_idx_;
|
|
if (offset < 0 || offset >= calculable_items_->count() ||
|
|
param_idx != calculable_items_->at(offset).hidden_idx_) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid param index", K(ret), K(param_idx), K(offset));
|
|
} else {
|
|
expr = calculable_items_->at(offset).expr_;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObStmtCompareContext::compare_set_op_expr(const ObSetOpRawExpr& left, const ObSetOpRawExpr& right)
|
|
{
|
|
bool bret = false;
|
|
int64_t pos = left.get_idx();
|
|
if (OB_UNLIKELY(pos < 0 || pos >= map_info_.select_item_map_.count()) ||
|
|
OB_INVALID_ID == map_info_.select_item_map_.at(pos)) {
|
|
//do nothing
|
|
} else {
|
|
bret = map_info_.select_item_map_.at(pos) == right.get_idx();
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
int ObStmtComparer::compute_stmt_overlap(const ObDMLStmt *first,
|
|
const ObDMLStmt *second,
|
|
ObStmtMapInfo &map_info)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t match_count = 0;
|
|
map_info.reset();
|
|
if (OB_ISNULL(first) || OB_ISNULL(second)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("stmts are null", K(ret), K(first), K(second));
|
|
} else if (OB_FAIL(compute_from_items_map(first,
|
|
second,
|
|
map_info,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute from items map", K(ret));
|
|
} else if (OB_FAIL(map_info.cond_map_.prepare_allocate(first->get_condition_size()))) {
|
|
LOG_WARN("failed to pre-allocate condition map", K(ret));
|
|
} else if (OB_FAIL(compute_conditions_map(first,
|
|
second,
|
|
first->get_condition_exprs(),
|
|
second->get_condition_exprs(),
|
|
map_info,
|
|
map_info.cond_map_,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute condition map", K(ret));
|
|
} else {
|
|
LOG_TRACE("stmt map info", K(map_info));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief ObTransformUtils::is_same_from
|
|
* 比较两个 From 项是否相同
|
|
* @return
|
|
*/
|
|
int ObStmtComparer::is_same_from(const ObDMLStmt *first,
|
|
const FromItem &first_from,
|
|
const ObDMLStmt *second,
|
|
const FromItem &second_from,
|
|
ObStmtMapInfo &map_info,
|
|
bool &is_same)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_same = false;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("stmts have null", K(ret), K(first), K(second));
|
|
} else if (first_from.is_joined_ && second_from.is_joined_) {
|
|
QueryRelation relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_FAIL(compare_joined_table_item(first,
|
|
first->get_joined_table(first_from.table_id_),
|
|
second,
|
|
second->get_joined_table(second_from.table_id_),
|
|
map_info,
|
|
relation))) {
|
|
LOG_WARN(" compare joined table item failed", K(ret));
|
|
} else if (QueryRelation::QUERY_EQUAL == relation) {
|
|
is_same = true;
|
|
} else {
|
|
/*do noting*/
|
|
}
|
|
} else if (!first_from.is_joined_ && !second_from.is_joined_) {
|
|
QueryRelation relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_FAIL(compare_table_item(first,
|
|
first->get_table_item_by_id(first_from.table_id_),
|
|
second,
|
|
second->get_table_item_by_id(second_from.table_id_),
|
|
map_info,
|
|
relation))) {
|
|
LOG_WARN(" compare table item failed", K(ret));
|
|
} else if (QueryRelation::QUERY_EQUAL == relation) {
|
|
is_same = true;
|
|
} else {
|
|
/*do noting*/
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::check_stmt_containment(const ObDMLStmt *first,
|
|
const ObDMLStmt *second,
|
|
ObStmtMapInfo &map_info,
|
|
QueryRelation &relation,
|
|
bool is_strict_select_list)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t first_count = 0;
|
|
int64_t second_count = 0;
|
|
int64_t match_count = 0;
|
|
ObSelectStmt *first_sel = NULL;
|
|
ObSelectStmt *second_sel = NULL;
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(first), K(second), K(ret));
|
|
} else if (!first->is_select_stmt() || !second->is_select_stmt()) {
|
|
/*do nothing*/
|
|
} else if (FALSE_IT(first_sel = const_cast<ObSelectStmt*>(static_cast<const ObSelectStmt*>(first)))) {
|
|
/*do nothing*/
|
|
} else if (FALSE_IT(second_sel = const_cast<ObSelectStmt*>(static_cast<const ObSelectStmt*>(second)))) {
|
|
/*do nothing*/
|
|
} else if (first_sel->has_recursive_cte() || second_sel->has_recursive_cte() ||
|
|
first_sel->has_hierarchical_query() || second_sel->has_hierarchical_query() ||
|
|
first_sel->is_contains_assignment() || second_sel->is_contains_assignment()) {
|
|
/*do nothing*/
|
|
} else if (first_sel->is_set_stmt() && second_sel->is_set_stmt()) {
|
|
if (OB_FAIL(compare_set_stmt(first_sel, second_sel, map_info, relation))) {
|
|
LOG_WARN("failed to compare set stmt", K(ret));
|
|
}
|
|
} else if (first_sel->is_set_stmt() || second_sel->is_set_stmt()) {
|
|
/*do nothing*/
|
|
} else if (first_sel->get_from_item_size() != second_sel->get_from_item_size()) {
|
|
/*do nothing*/
|
|
} else {
|
|
// check from items
|
|
if (OB_FAIL(compute_from_items_map(first_sel,
|
|
second_sel,
|
|
map_info,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute from items map", K(ret));
|
|
} else if (match_count != first_sel->get_from_item_size()) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check from item map", K(relation), K(map_info));
|
|
} else {
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
map_info.is_table_equal_ = true;
|
|
map_info.is_from_equal_ = true;
|
|
LOG_TRACE("succeed to check from item map", K(relation), K(map_info));
|
|
}
|
|
|
|
//check semi infos
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_EQUAL == relation) {
|
|
first_count = first_sel->get_semi_info_size();
|
|
second_count = second_sel->get_semi_info_size();
|
|
if (OB_FAIL(compute_semi_infos_map(first_sel,
|
|
second_sel,
|
|
map_info,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute semi info map", K(ret));
|
|
} else if (match_count == first_count && match_count == second_count) {
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
map_info.is_semi_info_equal_ = true;
|
|
LOG_TRACE("succeed to check semi info map", K(relation), K(map_info));
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check semi info map", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// check condition exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_EQUAL == relation) {
|
|
first_count = first_sel->get_condition_size();
|
|
second_count = second_sel->get_condition_size();
|
|
if (OB_FAIL(compute_conditions_map(first_sel,
|
|
second_sel,
|
|
first_sel->get_condition_exprs(),
|
|
second_sel->get_condition_exprs(),
|
|
map_info,
|
|
map_info.cond_map_,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute conditions map", K(ret));
|
|
} else if (match_count == first_count && match_count == second_count) {
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
map_info.is_cond_equal_ = true;
|
|
LOG_TRACE("succeed to check conditions map", K(relation), K(map_info));
|
|
} else if (match_count == first_count && match_count < second_count) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
LOG_TRACE("succeed to check conditions map", K(relation), K(map_info));
|
|
} else if (match_count < first_count && match_count == second_count) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
LOG_TRACE("succeed to check conditions map", K(relation), K(map_info));
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check conditions map", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// check group by exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
bool is_consistent = false;
|
|
first_count = first_sel->get_group_exprs().count();
|
|
second_count = second_sel->get_group_exprs().count();
|
|
int64_t first_rollup_count = first_sel->get_rollup_exprs().count();
|
|
int64_t second_rollup_count = second_sel->get_rollup_exprs().count();
|
|
if ((first_sel->get_aggr_item_size() > 0 ||
|
|
second_sel->get_aggr_item_size() > 0)
|
|
&& relation != QueryRelation::QUERY_EQUAL) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check group by map", K(relation), K(map_info));
|
|
} else if (first_rollup_count != second_rollup_count ||
|
|
first_count != second_count) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check group by map", K(relation), K(map_info));
|
|
} else if (0 == first_count && 0 == second_count &&
|
|
0 == first_rollup_count && 0 == second_rollup_count) {
|
|
map_info.is_group_equal_ = true;
|
|
} else if (OB_FAIL(ObTransformUtils::check_group_by_consistent(first_sel,
|
|
is_consistent))) {
|
|
LOG_WARN("failed to check whether group by is consistent", K(ret));
|
|
} else if (!is_consistent) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
} else if (OB_FAIL(ObTransformUtils::check_group_by_consistent(second_sel,
|
|
is_consistent))) {
|
|
LOG_WARN("failed to check whether group by is consistent", K(ret));
|
|
} else if (!is_consistent) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
} else if (OB_FAIL(map_info.group_map_.prepare_allocate(first_count))) {
|
|
LOG_WARN("failed to allcoate group by map", K(ret));
|
|
} else if (OB_FAIL(compute_conditions_map(first_sel,
|
|
second_sel,
|
|
first_sel->get_group_exprs(),
|
|
second_sel->get_group_exprs(),
|
|
map_info,
|
|
map_info.group_map_,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute group by expr map", K(ret));
|
|
} else if (match_count != first_count || match_count != second_count) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check group by map", K(relation), K(map_info));
|
|
} else if (first_rollup_count != 0) {
|
|
ObStmtCompareContext context(first_sel, second_sel, map_info, &first_sel->get_query_ctx()->calculable_items_);
|
|
bool rollup_match = true;
|
|
for (int64_t i = 0; OB_SUCC(ret) && rollup_match && i < first_rollup_count; i++) {
|
|
if (OB_FAIL(is_same_condition(first_sel->get_rollup_exprs().at(i),
|
|
second_sel->get_rollup_exprs().at(i),
|
|
context,
|
|
rollup_match))) {
|
|
LOG_WARN("failed to check is condition equal", K(ret));
|
|
}
|
|
}
|
|
map_info.is_group_equal_ = rollup_match;
|
|
LOG_TRACE("succeed to check group by map", K(relation), K(map_info));
|
|
} else {
|
|
// todo @guoping.wgp we can do better to check containment relationship for group by clause
|
|
map_info.is_group_equal_ = true;
|
|
LOG_TRACE("succeed to check group by map", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// check having exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
first_count = first_sel->get_having_expr_size();
|
|
second_count = second_sel->get_having_expr_size();
|
|
if (0 == first_count && 0 == second_count) {
|
|
map_info.is_having_equal_ = true;
|
|
} else if (OB_FAIL(compute_conditions_map(first_sel,
|
|
second_sel,
|
|
first_sel->get_having_exprs(),
|
|
second_sel->get_having_exprs(),
|
|
map_info,
|
|
map_info.having_map_,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute having expr map", K(ret));
|
|
} else if (match_count == first_count && match_count == second_count) {
|
|
map_info.is_having_equal_ = true;
|
|
LOG_TRACE("succeed to check having map", K(relation), K(map_info));
|
|
} else if (match_count == first_count && match_count < second_count &&
|
|
(relation == QueryRelation::QUERY_RIGHT_SUBSET ||
|
|
relation == QueryRelation::QUERY_EQUAL)) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
LOG_TRACE("succeed to check having map", K(relation), K(map_info));
|
|
} else if (match_count == second_count && match_count < first_count &&
|
|
(relation == QueryRelation::QUERY_LEFT_SUBSET ||
|
|
relation == QueryRelation::QUERY_EQUAL)) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
LOG_TRACE("succeed to check having map", K(relation), K(map_info));
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check having map", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// check window function exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
first_count = first_sel->get_window_func_count();
|
|
second_count = second_sel->get_window_func_count();
|
|
if (0 == first_count && 0 == second_count) {
|
|
/*do nothing*/
|
|
} else if (relation != QueryRelation::QUERY_EQUAL) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check window function map", K(relation), K(map_info));
|
|
} else {
|
|
LOG_TRACE("succeed to check window function map", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// check qualify filters
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
first_count = first_sel->get_qualify_filters_count();
|
|
second_count = second_sel->get_qualify_filters_count();
|
|
if (0 == first_count && 0 == second_count) {
|
|
map_info.is_qualify_filter_equal_ = true;
|
|
} else if (!ObOptimizerUtil::same_exprs(first_sel->get_qualify_filters(),
|
|
second_sel->get_qualify_filters())) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check qualify filters", K(relation), K(map_info));
|
|
} else {
|
|
map_info.is_qualify_filter_equal_ = true;
|
|
}
|
|
}
|
|
|
|
// check distinct exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
if ((!first_sel->has_distinct() && !second_sel->has_distinct()) ||
|
|
(first_sel->has_distinct() && second_sel->has_distinct())) {
|
|
map_info.is_distinct_equal_ = true;
|
|
LOG_TRACE("succeed to check distinct expr map", K(relation), K(map_info));
|
|
} else if (first_sel->has_distinct() && !second_sel->has_distinct() &&
|
|
(relation == QueryRelation::QUERY_LEFT_SUBSET ||
|
|
relation == QueryRelation::QUERY_EQUAL)) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
LOG_TRACE("succeed to check distinct expr map", K(relation), K(map_info));
|
|
} else if (!first_sel->has_distinct() && second_sel->has_distinct() &&
|
|
(relation == QueryRelation::QUERY_RIGHT_SUBSET ||
|
|
relation == QueryRelation::QUERY_EQUAL)) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
LOG_TRACE("succeed to check distinct expr map", K(relation), K(map_info));
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check distinct expr map", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// check order by exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
first_count = first->get_order_item_size();
|
|
second_count = second->get_order_item_size();
|
|
if (0 == first_count && 0 == second_count) {
|
|
map_info.is_order_equal_ = true;
|
|
} else if (first_count != second_count) {
|
|
// do nothing
|
|
} else if (OB_FAIL(compute_orderby_map(first_sel,
|
|
second_sel,
|
|
first_sel->get_order_items(),
|
|
second_sel->get_order_items(),
|
|
map_info,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute order item map", K(ret));
|
|
} else if (match_count == first_count && match_count == second_count) {
|
|
map_info.is_order_equal_ = true;
|
|
LOG_TRACE("succeed to check order item map", K(relation), K(map_info));
|
|
} else {
|
|
// The Order Item relation does not afftect the query relation
|
|
LOG_TRACE("succeed to check order item map", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// check limit exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
if (!first_sel->has_limit() && !second_sel->has_limit()) {
|
|
LOG_TRACE("succeed to check limit expr", K(relation), K(map_info));
|
|
} else if (first_sel->has_limit() && !second_sel->has_limit() &&
|
|
(relation == QueryRelation::QUERY_LEFT_SUBSET ||
|
|
relation == QueryRelation::QUERY_EQUAL)) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
LOG_TRACE("succeed to check limit expr", K(relation), K(map_info));
|
|
} else if (!first_sel->has_limit() && second_sel->has_limit() &&
|
|
(relation == QueryRelation::QUERY_RIGHT_SUBSET ||
|
|
relation == QueryRelation::QUERY_EQUAL)) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
LOG_TRACE("succeed to check limit expr", K(relation), K(map_info));
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check limit expr", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// compute map for select items output
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
ObSEArray<ObRawExpr*, 16> first_exprs;
|
|
ObSEArray<ObRawExpr*, 16> second_exprs;
|
|
if (OB_FAIL(first_sel->get_select_exprs(first_exprs))) {
|
|
LOG_WARN("failed to get select exprs", K(ret));
|
|
} else if (OB_FAIL(second_sel->get_select_exprs(second_exprs))) {
|
|
LOG_WARN("failed to get select exprs", K(ret));
|
|
} else if (OB_FAIL(compute_conditions_map(first_sel,
|
|
second_sel,
|
|
first_exprs,
|
|
second_exprs,
|
|
map_info,
|
|
map_info.select_item_map_,
|
|
match_count,
|
|
is_strict_select_list))) {
|
|
LOG_WARN("failed to compute output expr map", K(ret));
|
|
} else if (match_count == first_exprs.count() && match_count == second_exprs.count()) {
|
|
map_info.is_select_item_equal_ = true;
|
|
LOG_TRACE("succeed to check select item map", K(relation), K(map_info));
|
|
} else {
|
|
LOG_TRACE("succeed to check stmt containment", K(relation), K(map_info));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compute_from_items_map(const ObDMLStmt *first,
|
|
const ObDMLStmt *second,
|
|
ObStmtMapInfo &map_info,
|
|
int64_t &match_count)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
match_count = 0;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(first), K(second), K(ret));
|
|
} else if (OB_FAIL(map_info.table_map_.prepare_allocate(first->get_table_size()))) {
|
|
LOG_WARN("failed to pre-allocate table map", K(ret));
|
|
} else if (OB_FAIL(map_info.from_map_.prepare_allocate(first->get_from_item_size()))) {
|
|
LOG_WARN("failed to pre-allocate from map", K(ret));
|
|
} else if (OB_FAIL(map_info.view_select_item_map_.prepare_allocate(first->get_table_size()))) {
|
|
LOG_WARN("failed to pre-allocate generated table map", K(ret));
|
|
} else {
|
|
ObSqlBitSet<> matched_items;
|
|
for (int64_t i = 0; i < map_info.table_map_.count(); ++i) {
|
|
map_info.table_map_.at(i) = OB_INVALID_ID;
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < first->get_from_item_size(); ++i) {
|
|
const FromItem &first_from = first->get_from_item(i);
|
|
bool is_match = false;
|
|
map_info.from_map_.at(i) = OB_INVALID_ID;
|
|
for (int64_t j = 0; OB_SUCC(ret) && !is_match && j < second->get_from_item_size(); ++j) {
|
|
const FromItem &second_from = second->get_from_item(j);
|
|
if (matched_items.has_member(j)) {
|
|
// do nothing
|
|
} else if (OB_FAIL(is_same_from(first,
|
|
first_from,
|
|
second,
|
|
second_from,
|
|
map_info,
|
|
is_match))) {
|
|
LOG_WARN("failed to check the from item same", K(ret));
|
|
} else if (!is_match) {
|
|
// do nothing
|
|
} else if (OB_FAIL(matched_items.add_member(j))) {
|
|
LOG_WARN("failed to add member", K(ret));
|
|
} else {
|
|
match_count++;
|
|
map_info.from_map_.at(i) = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compute_conditions_map(const ObDMLStmt *first,
|
|
const ObDMLStmt *second,
|
|
const ObIArray<ObRawExpr*> &first_exprs,
|
|
const ObIArray<ObRawExpr*> &second_exprs,
|
|
ObStmtMapInfo &map_info,
|
|
ObIArray<int64_t> &condition_map,
|
|
int64_t &match_count,
|
|
bool is_same_by_order)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSqlBitSet<> matched_items;
|
|
ObStmtCompareContext context(first, second, map_info, &first->get_query_ctx()->calculable_items_);
|
|
match_count = 0;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second) || OB_ISNULL(first->get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(first), K(second), K(ret));
|
|
} else if (OB_FAIL(condition_map.prepare_allocate(first_exprs.count()))) {
|
|
LOG_WARN("failed to preallocate array", K(ret));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < first_exprs.count(); ++i) {
|
|
bool is_match = false;
|
|
condition_map.at(i) = OB_INVALID_ID;
|
|
if (!is_same_by_order) {
|
|
// is same to any one
|
|
for (int64_t j = 0; OB_SUCC(ret) && !is_match && j < second_exprs.count(); ++j) {
|
|
if (matched_items.has_member(j)) {
|
|
// do nothing
|
|
} else if (OB_FAIL(is_same_condition(first_exprs.at(i),
|
|
second_exprs.at(j),
|
|
context,
|
|
is_match))) {
|
|
LOG_WARN("failed to check is condition equal", K(ret));
|
|
} else if (!is_match) {
|
|
// do nothing
|
|
} else if (OB_FAIL(append(map_info.equal_param_map_, context.equal_param_info_))) {
|
|
LOG_WARN("failed to append exprs", K(ret));
|
|
} else if (OB_FAIL(matched_items.add_member(j))) {
|
|
LOG_WARN("failed to add member", K(ret));
|
|
} else {
|
|
match_count++;
|
|
condition_map.at(i) = j;
|
|
}
|
|
}
|
|
} else {
|
|
// is same by order
|
|
if (i < second_exprs.count()) {
|
|
if (OB_FAIL(is_same_condition(first_exprs.at(i),
|
|
second_exprs.at(i),
|
|
context,
|
|
is_match))) {
|
|
LOG_WARN("failed to check is condition equal", K(ret));
|
|
} else if (!is_match) {
|
|
// do nothing
|
|
} else if (OB_FAIL(append(map_info.equal_param_map_, context.equal_param_info_))) {
|
|
LOG_WARN("failed to append exprs", K(ret));
|
|
} else if (OB_FAIL(matched_items.add_member(i))) {
|
|
LOG_WARN("failed to add member", K(ret));
|
|
} else {
|
|
match_count++;
|
|
condition_map.at(i) = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compute_orderby_map(const ObDMLStmt *first,
|
|
const ObDMLStmt *second,
|
|
const ObIArray<OrderItem> &first_orders,
|
|
const ObIArray<OrderItem> &second_orders,
|
|
ObStmtMapInfo &map_info,
|
|
int64_t &match_count)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObStmtCompareContext context(first, second, map_info, &first->get_query_ctx()->calculable_items_);
|
|
match_count = 0;
|
|
bool first_match_all = true;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second) || OB_ISNULL(first->get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(first), K(second), K(ret));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && first_match_all && i < first_orders.count() && i < second_orders.count(); ++i) {
|
|
bool is_match = false;
|
|
if (first_orders.at(i).order_type_ != second_orders.at(i).order_type_) {
|
|
first_match_all = false;
|
|
} else if (OB_FAIL(is_same_condition(first_orders.at(i).expr_,
|
|
second_orders.at(i).expr_,
|
|
context,
|
|
is_match))) {
|
|
LOG_WARN("failed to check is condition equal", K(ret));
|
|
} else if (!is_match) {
|
|
first_match_all = false;
|
|
} else if (OB_FAIL(append(map_info.equal_param_map_, context.equal_param_info_))) {
|
|
LOG_WARN("failed to append exprs", K(ret));
|
|
} else {
|
|
match_count++;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::is_same_condition(const ObRawExpr *left,
|
|
const ObRawExpr *right,
|
|
ObStmtCompareContext &context,
|
|
bool &is_same)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_same = false;
|
|
context.equal_param_info_.reset();
|
|
if (OB_ISNULL(left) || OB_ISNULL(right)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("expr is null", K(ret));
|
|
} else if (!(is_same = left->same_as(*right, &context))) {
|
|
context.equal_param_info_.reset();
|
|
if (!IS_COMMON_COMPARISON_OP(left->get_expr_type()) ||
|
|
get_opposite_compare_type(left->get_expr_type()) != right->get_expr_type()) {
|
|
// do nothing
|
|
} else if (OB_ISNULL(left->get_param_expr(0)) ||
|
|
OB_ISNULL(left->get_param_expr(1)) ||
|
|
OB_ISNULL(right->get_param_expr(0)) ||
|
|
OB_ISNULL(right->get_param_expr(1))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("param exprs are null", K(ret));
|
|
} else if (!left->get_param_expr(0)->same_as(*right->get_param_expr(1), &context)) {
|
|
// do nothing
|
|
} else if (!left->get_param_expr(1)->same_as(*right->get_param_expr(0), &context)) {
|
|
// do nothing
|
|
} else {
|
|
is_same = true;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compute_semi_infos_map(const ObDMLStmt *first,
|
|
const ObDMLStmt *second,
|
|
ObStmtMapInfo &map_info,
|
|
int64_t &match_count)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSqlBitSet<> matched_items;
|
|
match_count = 0;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(first), K(second), K(ret));
|
|
} else if (OB_FAIL(map_info.semi_info_map_.prepare_allocate(first->get_semi_info_size()))) {
|
|
LOG_WARN("failed to pre-allocate generated table map", K(ret));
|
|
} else {
|
|
const ObIArray<SemiInfo*> &first_semi_infos = first->get_semi_infos();
|
|
const ObIArray<SemiInfo*> &second_semi_infos = second->get_semi_infos();
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < first_semi_infos.count(); ++i) {
|
|
bool is_match = false;
|
|
map_info.semi_info_map_.at(i) = OB_INVALID_ID;
|
|
for (int64_t j = 0; OB_SUCC(ret) && !is_match && j < second_semi_infos.count(); ++j) {
|
|
if (matched_items.has_member(j)) {
|
|
// do nothing
|
|
} else if (OB_FAIL(is_same_semi_info(first,
|
|
first_semi_infos.at(i),
|
|
second,
|
|
second_semi_infos.at(j),
|
|
map_info,
|
|
is_match))) {
|
|
LOG_WARN("failed to check is condition equal", K(ret));
|
|
} else if (!is_match) {
|
|
// do nothing
|
|
} else if (OB_FAIL(matched_items.add_member(j))) {
|
|
LOG_WARN("failed to add member", K(ret));
|
|
} else {
|
|
match_count++;
|
|
map_info.semi_info_map_.at(i) = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::is_same_semi_info(const ObDMLStmt *first,
|
|
const SemiInfo *first_semi_info,
|
|
const ObDMLStmt *second,
|
|
const SemiInfo *second_semi_info,
|
|
ObStmtMapInfo &map_info,
|
|
bool &is_same)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_same = false;
|
|
if (OB_ISNULL(first) || OB_ISNULL(first_semi_info) ||
|
|
OB_ISNULL(second) || OB_ISNULL(second_semi_info)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect null param", K(ret));
|
|
} else if (first_semi_info->join_type_ != second_semi_info->join_type_) {
|
|
//do nothing
|
|
} else {
|
|
int64_t match_count = 0;
|
|
//check left tables
|
|
ObSEArray<int64_t, 4> table_map;
|
|
if (OB_FAIL(compute_tables_map(first,
|
|
second,
|
|
first_semi_info->left_table_ids_,
|
|
second_semi_info->left_table_ids_,
|
|
map_info,
|
|
table_map,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute tables map", K(ret));
|
|
} else if (match_count == first_semi_info->left_table_ids_.count() &&
|
|
match_count == second_semi_info->left_table_ids_.count()) {
|
|
is_same = true;
|
|
} else {
|
|
is_same = false;
|
|
}
|
|
//check right table
|
|
if (OB_SUCC(ret) && is_same) {
|
|
const TableItem *first_table = first->get_table_item_by_id(first_semi_info->right_table_id_);
|
|
const TableItem *second_table = second->get_table_item_by_id(second_semi_info->right_table_id_);
|
|
QueryRelation relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_FAIL(compare_table_item(first,
|
|
first_table,
|
|
second,
|
|
second_table,
|
|
map_info,
|
|
relation))) {
|
|
LOG_WARN("failed to compare table item", K(ret));
|
|
} else if (QueryRelation::QUERY_EQUAL == relation) {
|
|
is_same = true;
|
|
} else {
|
|
is_same = false;
|
|
}
|
|
}
|
|
//check semi condition
|
|
if (OB_SUCC(ret) && is_same) {
|
|
ObSEArray<int64_t, 4> condition_map;
|
|
if (OB_FAIL(compute_conditions_map(first,
|
|
second,
|
|
first_semi_info->semi_conditions_,
|
|
second_semi_info->semi_conditions_,
|
|
map_info,
|
|
condition_map,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute conditions map", K(ret));
|
|
} else if (match_count == first_semi_info->semi_conditions_.count() &&
|
|
match_count == second_semi_info->semi_conditions_.count()) {
|
|
is_same = true;
|
|
} else {
|
|
is_same = false;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compute_tables_map(const ObDMLStmt *first,
|
|
const ObDMLStmt *second,
|
|
const ObIArray<uint64_t> &first_table_ids,
|
|
const ObIArray<uint64_t> &second_table_ids,
|
|
ObStmtMapInfo &map_info,
|
|
ObIArray<int64_t> &table_map,
|
|
int64_t &match_count)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSqlBitSet<> matched_items;
|
|
ObStmtCompareContext context(first, second, map_info, &first->get_query_ctx()->calculable_items_);
|
|
match_count = 0;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second) || OB_ISNULL(first->get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(first), K(second), K(ret));
|
|
} else if (OB_FAIL(table_map.prepare_allocate(first_table_ids.count()))) {
|
|
LOG_WARN("failed to preallocate array", K(ret));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < first_table_ids.count(); ++i) {
|
|
bool is_match = false;
|
|
table_map.at(i) = OB_INVALID_ID;
|
|
for (int64_t j = 0; OB_SUCC(ret) && !is_match && j < second_table_ids.count(); ++j) {
|
|
if (matched_items.has_member(j)) {
|
|
// do nothing
|
|
} else if (context.get_table_map_idx(first_table_ids.at(i), second_table_ids.at(j)) == OB_INVALID_ID) {
|
|
//do nothing
|
|
} else if (OB_FAIL(matched_items.add_member(j))) {
|
|
LOG_WARN("failed to add member", K(ret));
|
|
} else {
|
|
match_count++;
|
|
table_map.at(i) = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
int ObStmtComparer::compare_basic_table_item(const ObDMLStmt *first,
|
|
const TableItem *first_table,
|
|
const ObDMLStmt *second,
|
|
const TableItem *second_table,
|
|
QueryRelation &relation)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_ISNULL(first) || OB_ISNULL(first_table)
|
|
|| OB_ISNULL(second) || OB_ISNULL(second_table)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("param has null", K(first), K(first_table), K(second), K(second_table));
|
|
} else if ((first_table->is_basic_table() || first_table->is_link_table()) &&
|
|
(second_table->is_basic_table() || second_table->is_link_table()) &&
|
|
first_table->ref_id_ == second_table->ref_id_ &&
|
|
first_table->flashback_query_type_ == second_table->flashback_query_type_ &&
|
|
(first_table->flashback_query_expr_ == second_table->flashback_query_expr_ ||
|
|
first_table->flashback_query_expr_->same_as(*second_table->flashback_query_expr_))) {
|
|
if (OB_LIKELY(first_table->access_all_part() && second_table->access_all_part())) {
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
} else if (first_table->access_all_part()) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
} else if (second_table->access_all_part()) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
} else {
|
|
// part ids for subpartition is a large int64_t number, here can not use bit set.
|
|
bool left_subset = ObOptimizerUtil::is_subset(first_table->part_ids_,
|
|
second_table->part_ids_);
|
|
bool right_subset = ObOptimizerUtil::is_subset(second_table->part_ids_,
|
|
first_table->part_ids_);
|
|
if (left_subset && right_subset) {
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
} else if (left_subset) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
} else if (right_subset) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
}
|
|
}
|
|
} else {
|
|
/*do nothing*/
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compare_joined_table_item (const ObDMLStmt *first,
|
|
const TableItem *first_table,
|
|
const ObDMLStmt *second,
|
|
const TableItem *second_table,
|
|
ObStmtMapInfo &map_info,
|
|
QueryRelation &relation)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
QueryRelation left_relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
QueryRelation right_relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_ISNULL(first) || OB_ISNULL(first_table)
|
|
|| OB_ISNULL(second) || OB_ISNULL(second_table)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("param has null", K(first), K(first_table), K(second), K(second_table));
|
|
} else if (first_table->is_joined_table() && second_table->is_joined_table()) {
|
|
const JoinedTable *first_joined_table = static_cast<const JoinedTable *>(first_table);
|
|
const JoinedTable *second_joined_table = static_cast<const JoinedTable *>(second_table);
|
|
int64_t first_count = first_joined_table->join_conditions_.count();
|
|
int64_t second_count = second_joined_table->join_conditions_.count();
|
|
ObSEArray<int64_t, 4> condition_map;
|
|
int64_t match_count = 0;
|
|
if (first_joined_table->joined_type_ != second_joined_table->joined_type_) {
|
|
/*do nothing*/
|
|
} else if (OB_FAIL(SMART_CALL(compare_joined_table_item(first,
|
|
first_joined_table->left_table_,
|
|
second,
|
|
second_joined_table->left_table_,
|
|
map_info,
|
|
left_relation)))) {
|
|
LOG_WARN("compare joined table failed", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(compare_joined_table_item(first,
|
|
first_joined_table->right_table_,
|
|
second,
|
|
second_joined_table->right_table_,
|
|
map_info,
|
|
right_relation)))) {
|
|
LOG_WARN("compare joined table failed", K(ret));
|
|
} else if (left_relation != QueryRelation::QUERY_EQUAL ||
|
|
right_relation != QueryRelation::QUERY_EQUAL) {
|
|
if (first_joined_table->joined_type_ != INNER_JOIN &&
|
|
first_joined_table->joined_type_ != FULL_OUTER_JOIN) {
|
|
//inner join、full outer join需要交换左右表检查
|
|
} else if (OB_FAIL(SMART_CALL(compare_joined_table_item(first,
|
|
first_joined_table->left_table_,
|
|
second,
|
|
second_joined_table->right_table_,
|
|
map_info,
|
|
left_relation)))) {
|
|
LOG_WARN("compare joined table failed", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(compare_joined_table_item(first,
|
|
first_joined_table->right_table_,
|
|
second,
|
|
second_joined_table->left_table_,
|
|
map_info,
|
|
right_relation)))) {
|
|
LOG_WARN("compare joined table failed", K(ret));
|
|
}
|
|
} else {/*do nothing*/}
|
|
if (OB_FAIL(ret)) {
|
|
/*do nothing*/
|
|
} else if (left_relation != QueryRelation::QUERY_EQUAL ||
|
|
right_relation != QueryRelation::QUERY_EQUAL) {
|
|
//do nothing
|
|
} else if (OB_FAIL(compute_conditions_map(first,
|
|
second,
|
|
first_joined_table->join_conditions_,
|
|
second_joined_table->join_conditions_,
|
|
map_info,
|
|
condition_map,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute conditions map", K(ret));
|
|
} else if (match_count != first_count || match_count != second_count) {
|
|
//on condition不相同
|
|
} else {
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
}
|
|
} else if (OB_FAIL(compare_table_item(first,
|
|
first_table,
|
|
second,
|
|
second_table,
|
|
map_info,
|
|
relation))) {
|
|
LOG_WARN("failed to compare table item", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compare_table_item(const ObDMLStmt *first,
|
|
const TableItem *first_table,
|
|
const ObDMLStmt *second,
|
|
const TableItem *second_table,
|
|
ObStmtMapInfo &map_info,
|
|
QueryRelation &relation)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second) ||
|
|
OB_ISNULL(first_table) || OB_ISNULL(second_table)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("stmts have null", K(ret), K(first), K(second));
|
|
} else if (map_info.table_map_.count() < first->get_table_size() &&
|
|
OB_FAIL(map_info.table_map_.prepare_allocate(first->get_table_size()))) {
|
|
LOG_WARN("failed to pre-allocate table map", K(ret));
|
|
} else if (map_info.view_select_item_map_.count() < first->get_table_size() &&
|
|
OB_FAIL(map_info.view_select_item_map_.prepare_allocate(first->get_table_size()))) {
|
|
LOG_WARN("failed to pre-allocate generated table map", K(ret));
|
|
} else if (first_table->for_update_ || second_table->for_update_) {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
} else if (first_table->is_temp_table() && second_table->is_temp_table()) {
|
|
if (first_table->ref_query_ == second_table->ref_query_) {
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
const int32_t first_table_index = first->get_table_bit_index(first_table->table_id_);
|
|
const int32_t second_table_index = second->get_table_bit_index(second_table->table_id_);
|
|
if (first_table_index < 1 || first_table_index > first->get_table_size()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect table bit index", K(ret));
|
|
} else {
|
|
map_info.table_map_.at(first_table_index - 1) = second_table_index - 1;
|
|
}
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
}
|
|
} else if ((first_table->is_basic_table() || first_table->is_link_table()) &&
|
|
(second_table->is_basic_table() || second_table->is_link_table())) {
|
|
if (OB_FAIL(compare_basic_table_item(first,
|
|
first_table,
|
|
second,
|
|
second_table,
|
|
relation))) {
|
|
LOG_WARN("compare table part failed",K(ret), K(first_table), K(second_table));
|
|
} else if (QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
const int32_t first_table_index = first->get_table_bit_index(first_table->table_id_);
|
|
const int32_t second_table_index = second->get_table_bit_index(second_table->table_id_);
|
|
if (first_table_index < 1 || first_table_index > first->get_table_size()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect table bit index", K(ret));
|
|
} else {
|
|
map_info.table_map_.at(first_table_index - 1) = second_table_index - 1;
|
|
}
|
|
}
|
|
//TODO:jiangxiu.wt 后续打开flashback query针对view和generated table的支持,这里需要处理
|
|
} else if (first_table->is_generated_table() &&
|
|
second_table->is_generated_table()) {
|
|
ObStmtMapInfo ref_query_map_info;
|
|
const int32_t first_table_index = first->get_table_bit_index(first_table->table_id_);
|
|
const int32_t second_table_index = second->get_table_bit_index(second_table->table_id_);
|
|
if (first_table_index < 1 || first_table_index > first->get_table_size()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect table bit index", K(ret));
|
|
} else if (OB_FAIL(SMART_CALL(check_stmt_containment(first_table->ref_query_,
|
|
second_table->ref_query_,
|
|
ref_query_map_info,
|
|
relation)))) {
|
|
LOG_WARN("check stmt containment failed", K(ret));
|
|
} else if (OB_FAIL(map_info.view_select_item_map_.at(first_table_index - 1).assign(ref_query_map_info.select_item_map_))) {
|
|
LOG_WARN("failed to assign select item map", K(ret));
|
|
} else if (QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
if (ref_query_map_info.is_select_item_equal_ && QueryRelation::QUERY_EQUAL == relation) {
|
|
map_info.table_map_.at(first_table_index - 1) = second_table_index - 1;
|
|
if (OB_FAIL(append(map_info.equal_param_map_, ref_query_map_info.equal_param_map_))) {
|
|
LOG_WARN("failed to append equal param", K(ret));
|
|
}
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
}
|
|
}
|
|
} else if (first_table->is_joined_table() &&
|
|
second_table->is_joined_table()) {
|
|
if (OB_FAIL(compare_joined_table_item(first,
|
|
first_table,
|
|
second,
|
|
second_table,
|
|
map_info,
|
|
relation))) {
|
|
LOG_WARN("failed to compare joined table item", K(ret));
|
|
}
|
|
} else if (first_table->is_values_table() && second_table->is_values_table()) {
|
|
if (OB_FAIL(compare_values_table_item(first,
|
|
first_table,
|
|
second,
|
|
second_table,
|
|
map_info,
|
|
relation))) {
|
|
LOG_WARN("compare values table failed",K(ret), K(first_table), K(second_table));
|
|
} else if (QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
const int32_t first_table_index = first->get_table_bit_index(first_table->table_id_);
|
|
const int32_t second_table_index = second->get_table_bit_index(second_table->table_id_);
|
|
if (first_table_index < 1 || first_table_index > first->get_table_size()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect table bit index", K(ret), K(first_table_index), K(first->get_table_size()));
|
|
} else {
|
|
map_info.table_map_.at(first_table_index - 1) = second_table_index - 1;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compare_set_stmt(const ObSelectStmt *first,
|
|
const ObSelectStmt *second,
|
|
ObStmtMapInfo &map_info,
|
|
QueryRelation &relation)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_ISNULL(first) || OB_ISNULL(second)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("stmts have null", K(ret), K(first), K(second));
|
|
} else if (!first->is_set_stmt() || !second->is_set_stmt()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("expect set stmt", KPC(first), KPC(second), K(ret));
|
|
} else if (first->is_recursive_union() || second->is_recursive_union()) {
|
|
//do nothing
|
|
} else if (first->get_set_query().count() != second->get_set_query().count()) {
|
|
//do nothing
|
|
} else {
|
|
QueryRelation set_query_relation = QueryRelation::QUERY_EQUAL;
|
|
for (int64_t i = 0; OB_SUCC(ret) && QueryRelation::QUERY_EQUAL == set_query_relation &&
|
|
i < first->get_set_query().count(); ++i) {
|
|
ObStmtMapInfo ref_query_map_info;
|
|
if (OB_FAIL(SMART_CALL(check_stmt_containment(first->get_set_query(i),
|
|
second->get_set_query(i),
|
|
ref_query_map_info,
|
|
set_query_relation)))) {
|
|
LOG_WARN("check stmt containment failed", K(ret));
|
|
} else if (QueryRelation::QUERY_EQUAL == set_query_relation && ref_query_map_info.is_select_item_equal_) {
|
|
if (OB_FAIL(map_info.view_select_item_map_.push_back(ref_query_map_info.select_item_map_))) {
|
|
LOG_WARN("failed to push back map info", K(ret));
|
|
} else if (OB_FAIL(append(map_info.equal_param_map_, ref_query_map_info.equal_param_map_))) {
|
|
LOG_WARN("failed to append equal param", K(ret));
|
|
}
|
|
} else {
|
|
set_query_relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_EQUAL == set_query_relation) {
|
|
map_info.is_select_item_equal_ = true;
|
|
for (int64_t i = 0; OB_SUCC(ret) && QueryRelation::QUERY_EQUAL == set_query_relation
|
|
&& i < map_info.view_select_item_map_.count(); ++i) {
|
|
const ObIArray<int64_t> &select_item_map = map_info.view_select_item_map_.at(i);
|
|
if (0 == i) {
|
|
if (OB_FAIL(map_info.select_item_map_.assign(select_item_map))) {
|
|
LOG_WARN("failed to assign select item map info", K(ret));
|
|
}
|
|
} else if (map_info.select_item_map_.count() != select_item_map.count()) {
|
|
set_query_relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
map_info.is_select_item_equal_ = false;
|
|
} else {
|
|
for (int64_t j = 0; OB_SUCC(ret) && QueryRelation::QUERY_EQUAL == set_query_relation &&
|
|
j < map_info.select_item_map_.count(); ++j) {
|
|
if (map_info.select_item_map_.at(j) != select_item_map.at(j) ||
|
|
OB_INVALID_ID == map_info.select_item_map_.at(j)) {
|
|
set_query_relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
map_info.is_select_item_equal_ = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_EQUAL == set_query_relation) {
|
|
if (first->get_set_op() == second->get_set_op() &&
|
|
((first->is_set_distinct() && second->is_set_distinct()) ||
|
|
(!first->is_set_distinct() && !second->is_set_distinct()))) {
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
} else if (ObSelectStmt::UNION == first->get_set_op() && !first->is_set_distinct()) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
} else if (ObSelectStmt::UNION == second->get_set_op() && !second->is_set_distinct()) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
} else if (ObSelectStmt::UNION == first->get_set_op()) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
} else if (ObSelectStmt::UNION == second->get_set_op()) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
}
|
|
}
|
|
|
|
// check order by exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
int64_t first_count = first->get_order_item_size();
|
|
int64_t second_count = second->get_order_item_size();
|
|
int64_t match_count = 0;
|
|
if (0 == first_count && 0 == second_count) {
|
|
map_info.is_order_equal_ = true;
|
|
} else if (first_count != second_count) {
|
|
// do nothing
|
|
} else if (OB_FAIL(compute_orderby_map(first,
|
|
second,
|
|
first->get_order_items(),
|
|
second->get_order_items(),
|
|
map_info,
|
|
match_count))) {
|
|
LOG_WARN("failed to compute order item map", K(ret));
|
|
} else if (match_count == first_count && match_count == second_count) {
|
|
map_info.is_order_equal_ = true;
|
|
LOG_TRACE("succeed to check order item map", K(relation), K(map_info));
|
|
} else {
|
|
// The Order Item relation does not afftect the query relation
|
|
LOG_TRACE("succeed to check order item map", K(relation), K(map_info));
|
|
}
|
|
}
|
|
|
|
// check limit exprs
|
|
if (OB_SUCC(ret) && QueryRelation::QUERY_UNCOMPARABLE != relation) {
|
|
if (!first->has_limit() && !second->has_limit()) {
|
|
LOG_TRACE("succeed to check limit expr", K(relation), K(map_info));
|
|
} else if (first->has_limit() && !second->has_limit() &&
|
|
(relation == QueryRelation::QUERY_LEFT_SUBSET ||
|
|
relation == QueryRelation::QUERY_EQUAL)) {
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
LOG_TRACE("succeed to check limit expr", K(relation), K(map_info));
|
|
} else if (!first->has_limit() && second->has_limit() &&
|
|
(relation == QueryRelation::QUERY_RIGHT_SUBSET ||
|
|
relation == QueryRelation::QUERY_EQUAL)) {
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
LOG_TRACE("succeed to check limit expr", K(relation), K(map_info));
|
|
} else {
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
LOG_TRACE("succeed to check limit expr", K(relation), K(map_info));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObStmtComparer::compare_values_table_item(const ObDMLStmt *first,
|
|
const TableItem *first_table,
|
|
const ObDMLStmt *second,
|
|
const TableItem *second_table,
|
|
ObStmtMapInfo &map_info,
|
|
QueryRelation &relation)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObStmtCompareContext context(first, second, map_info, &first->get_query_ctx()->calculable_items_);
|
|
relation = QueryRelation::QUERY_UNCOMPARABLE;
|
|
if (OB_ISNULL(first) || OB_ISNULL(first_table)
|
|
|| OB_ISNULL(second) || OB_ISNULL(second_table)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("param has null", K(first), K(first_table), K(second), K(second_table));
|
|
} else if (first_table->is_values_table() &&
|
|
second_table->is_values_table() &&
|
|
first->get_column_size(first_table->table_id_) == second->get_column_size(second_table->table_id_) &&
|
|
first_table->table_values_.count() % first->get_column_size(first_table->table_id_) == 0 &&
|
|
second_table->table_values_.count() % second->get_column_size(second_table->table_id_) == 0) {
|
|
//Perhaps in the future, the comparison of different row orders can be considered
|
|
int64_t match_count = 0;
|
|
bool is_match = true;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_match && i < first_table->table_values_.count(); ++i) {
|
|
bool is_match = false;
|
|
if (i >= second_table->table_values_.count()) {
|
|
break;
|
|
} else if (OB_FAIL(is_same_condition(first_table->table_values_.at(i),
|
|
second_table->table_values_.at(i),
|
|
context,
|
|
is_match))) {
|
|
LOG_WARN("failed to check is condition equal", K(ret));
|
|
} else if (!is_match) {
|
|
// do nothing
|
|
} else if (OB_FAIL(append(map_info.equal_param_map_, context.equal_param_info_))) {
|
|
LOG_WARN("failed to append exprs", K(ret));
|
|
} else {
|
|
++match_count;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && is_match) {
|
|
if (match_count == first_table->table_values_.count() &&
|
|
match_count == second_table->table_values_.count()) {//first table is equal second table
|
|
relation = QueryRelation::QUERY_EQUAL;
|
|
} else if (match_count == first_table->table_values_.count()) {//first table is subset second table
|
|
relation = QueryRelation::QUERY_LEFT_SUBSET;
|
|
} else if (match_count == second_table->table_values_.count()) {////second table is subset first table
|
|
relation = QueryRelation::QUERY_RIGHT_SUBSET;
|
|
}
|
|
}
|
|
} else {
|
|
/*do nothing*/
|
|
}
|
|
return ret;
|
|
}
|