Files
oceanbase/src/sql/rewrite/ob_key_part.cpp
chaser-ch 566e920620 Merge branch 'column_store'
Co-authored-by: wangt1xiuyi <13547954130@163.com>
Co-authored-by: yangqise7en <877793735@qq.com>
Co-authored-by: Zach41 <zach_41@163.com>
2023-10-31 15:39:22 +00:00

1670 lines
60 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/resolver/dml/ob_dml_stmt.h"
#include "sql/rewrite/ob_key_part.h"
#include "sql/rewrite/ob_query_range.h"
#include "sql/engine/expr/ob_expr_result_type_util.h"
#include "sql/optimizer/ob_optimizer_util.h"
namespace oceanbase
{
using namespace common;
namespace sql
{
void ObKeyPart::reset()
{
common::ObDLinkBase<ObKeyPart>::reset();
reset_key();
id_.table_id_ = OB_INVALID_ID;
id_.column_id_ = OB_INVALID_ID;
pos_.offset_ = -1;
key_type_ = T_NORMAL_KEY;
item_next_ = NULL;
or_next_ = NULL;
and_next_ = NULL;
rowid_column_idx_ = OB_INVALID_ID;
is_phy_rowid_key_part_ = false;
}
void ObKeyPart::reset_key()
{
if (is_normal_key()) {
normal_keypart_->start_.reset();
normal_keypart_->end_.reset();
normal_keypart_->always_true_ = false;
normal_keypart_->always_false_ = false;
normal_keypart_->include_start_ = false;
normal_keypart_->include_end_ = false;
} else if (is_like_key()) {
like_keypart_->pattern_.reset();
like_keypart_->escape_.reset();
} else if (is_in_key()) {
in_keypart_->reset();
} else if (is_geo_key()) {
geo_keypart_->wkb_.reset();
geo_keypart_->distance_.reset();
}
}
// can be unioned as one
// ignore the edge, k1 >= 0 or k1 < 0 can union as (min, max)
// return true if union happened, otherwise false
bool ObKeyPart::union_key(const ObKeyPart *other)
{
bool has_union = true;
if (OB_UNLIKELY(NULL == other)
|| OB_UNLIKELY(!is_normal_key())
|| OB_UNLIKELY(!other->is_normal_key())) {
has_union = false;
} else {
if (is_question_mark()
|| other->is_question_mark()
|| NULL != item_next_
|| NULL != other->item_next_
|| is_always_false()
|| other->is_always_false()
|| (is_phy_rowid_key_part() != other->is_phy_rowid_key_part())) {
has_union = false;
} else {
ObObj &s1 = normal_keypart_->start_;
ObObj &e1 = normal_keypart_->end_;
ObObj &s2 = other->normal_keypart_->start_;
ObObj &e2 = other->normal_keypart_->end_;
int cmp_s2_e1 = 0;
int cmp_e2_s1 = 0;
if ((cmp_s2_e1 = s2.compare(e1)) > 0 || (cmp_e2_s1 = e2.compare(s1)) < 0) {
has_union = false;
} else if (OB_UNLIKELY(0 == cmp_s2_e1)) {
if (!normal_keypart_->include_end_ && !other->normal_keypart_->include_start_) {
has_union = false;
}
} else if (OB_UNLIKELY(0 == cmp_e2_s1)) {
if (!normal_keypart_->include_start_ && !other->normal_keypart_->include_end_) {
has_union = false;
}
} // a < 0 or a > 0 can't be union as (MIN, MAX)
if (has_union) {
int cmp = s2.compare(s1);
if (cmp < 0) {
s1 = s2;
normal_keypart_->include_start_ = other->normal_keypart_->include_start_;
} else if (0 == cmp) {
normal_keypart_->include_start_ =
(normal_keypart_->include_start_ || other->normal_keypart_->include_start_);
if (normal_keypart_->include_start_ && s1.is_null()) {
null_safe_ = null_safe_ || other->null_safe_;
}
}
cmp = e2.compare(e1);
if (cmp > 0) {
e1 = e2;
normal_keypart_->include_end_ = other->normal_keypart_->include_end_;
} else if (0 == cmp) {
normal_keypart_->include_end_ =
(normal_keypart_->include_end_ || other->normal_keypart_->include_end_);
if (normal_keypart_->include_end_ && e1.is_null()) {
null_safe_ = null_safe_ || other->null_safe_;
}
}
}
}
}
return has_union;
}
bool ObKeyPart::equal_to(const ObKeyPart *other)
{
bool bret = true;
if (OB_UNLIKELY(NULL == other)) {
bret = false;
} else {
// 1. check item list
ObKeyPart *item_this = this;
const ObKeyPart *item_other = other;
bool is_done = false;
while (!is_done && NULL != item_this && NULL != item_other) {
if (!item_this->key_node_is_equal(item_other)) {
bret = false;
is_done = true;
} else {
item_this = item_this->item_next_;
item_other = item_other->item_next_;
if (NULL == item_this || NULL == item_other) {
// not both NULL
if (item_this != item_other) {
bret = false;
is_done = true;
}
}
}
}
// 2. check and_next_
if (bret) {
if (NULL != and_next_) {
bret = and_next_->equal_to(other->and_next_);
} else if (NULL != other->and_next_) {
bret = false;
}
}
// 3. check or_next_
if (bret) {
bool is_over = false;
item_this = or_next_;
item_other = other->or_next_;
while (!is_over && NULL != item_this && NULL != item_other) {
if (!item_this->equal_to(item_other)) {
bret = false;
is_over = true;
} else {
item_this = item_this->item_next_;
item_other = item_other->item_next_;
if (NULL == item_this || NULL == item_other) {
// not both NULL
if (item_this != item_other) {
bret = false;
is_over = true;
}
}
}
}
}
}
return bret;
}
bool ObKeyPart::key_node_is_equal(const ObKeyPart *other)
{
bool ret = true;
if (OB_UNLIKELY(other == NULL)) {
ret = false;
} else if (is_normal_key() && other->is_normal_key()) {
ret = (!is_question_mark() && !(other->is_question_mark()))
&& (is_phy_rowid_key_part_ == other->is_phy_rowid_key_part_)
&& (id_ == other->id_)
&& (pos_ == other->pos_)
&& (normal_keypart_->start_ == other->normal_keypart_->start_)
&& (normal_keypart_->end_ == other->normal_keypart_->end_)
&& (normal_keypart_->include_start_ == other->normal_keypart_->include_start_)
&& (normal_keypart_->include_end_ == other->normal_keypart_->include_end_)
&& (NULL == item_next_)
&& (NULL == other->item_next_);
} else if (is_in_key() && other->is_in_key()) {
if (is_question_mark() || other->is_question_mark() ||
!in_keypart_->offsets_same_to(other->in_keypart_)) {
ret = false;
} else {
// cur in key already has same param count to other if reach here
int64_t param_cnt = in_keypart_->in_params_.count();
for (int64_t i = 0; ret && i < param_cnt; ++i) {
InParamMeta *left = in_keypart_->in_params_.at(i);
InParamMeta *right = other->in_keypart_->in_params_.at(i);
if (OB_UNLIKELY(left == NULL || right == NULL ||
left->pos_ != right->pos_ ||
left->vals_.count() != right->vals_.count())) {
ret = false;
} else {
for (int64_t j = 0; ret && j < left->vals_.count(); ++j) {
if (left->vals_.at(j) != right->vals_.at(j)) {
ret = false;
}
}
}
}
}
} else { // like key is regarded as not equal
ret = false;
}
return ret;
}
bool ObKeyPart::is_equal_condition() const
{
bool bret = false;
for (const ObKeyPart *cur_key = this; !bret && cur_key != NULL; cur_key = cur_key->item_next_) {
if (cur_key->is_in_key()) {
bret = true;
} else if (cur_key->is_always_false() || cur_key->is_always_true()) {
bret = false;
} else if (cur_key->is_normal_key()) {
if (!cur_key->normal_keypart_->include_end_ || !cur_key->normal_keypart_->include_start_) {
bret = false;
} else if (cur_key->normal_keypart_->start_.get_type() != cur_key->normal_keypart_->end_.get_type()) {
bret = false;
} else if (cur_key->normal_keypart_->start_.is_unknown() && cur_key->normal_keypart_->end_.is_unknown()) {
bret = (cur_key->normal_keypart_->start_.get_unknown() == cur_key->normal_keypart_->end_.get_unknown());
} else if (0 == cur_key->normal_keypart_->start_.compare(cur_key->normal_keypart_->end_)) {
bret = true;
}
}
}
return bret;
}
// item next is not expected here
bool ObKeyPart::is_range_condition() const
{
bool bret = false;
if (is_always_false() || is_always_true() || item_next_ != NULL) {
bret = false;
} else if (is_normal_key() || is_in_key()) {
bret = true;
}
return bret;
}
bool ObKeyPart::is_question_mark() const
{
bool bret = false;
if (is_like_key()) {
bret = like_keypart_->pattern_.is_unknown() || like_keypart_->escape_.is_unknown();
} else if (is_normal_key()) {
bret = normal_keypart_->start_.is_unknown() || normal_keypart_->end_.is_unknown();
} else if (is_in_key()) {
bret = in_keypart_->contain_questionmark_;
} else if (is_geo_key()) {
bret = geo_keypart_->wkb_.is_unknown();
}
return bret;
}
bool ObKeyPart::has_intersect(const ObKeyPart *other) const
{
bool bret = true;
if (OB_UNLIKELY(NULL == other)
|| OB_UNLIKELY(!is_normal_key())
|| OB_UNLIKELY(!other->is_normal_key())) {
bret = false;
} else {
ObObj &s1 = normal_keypart_->start_;
ObObj &e1 = normal_keypart_->end_;
bool s1_flag = normal_keypart_->include_start_;
bool e1_flag = normal_keypart_->include_end_;
ObObj &s2 = other->normal_keypart_->start_;
bool s2_flag = other->normal_keypart_->include_start_;
ObObj &e2 = other->normal_keypart_->end_;
bool e2_flag = other->normal_keypart_->include_end_;
int cmp_s2_e1 = 0;
int cmp_e2_s1 = 0;
if ((cmp_s2_e1 = s2.compare(e1)) > 0 || (cmp_e2_s1 = e2.compare(s1)) < 0
|| (0 == cmp_s2_e1 && (false == s2_flag || false == e1_flag))
|| (0 == cmp_e2_s1 && (false == e2_flag || false == s1_flag))) {
bret = false;
}
}
return bret;
}
int ObKeyPart::intersect(ObKeyPart *other, bool contain_row)
{
UNUSED(contain_row);
int ret = OB_SUCCESS;
if (OB_UNLIKELY(NULL == other)) {
ret = OB_INVALID_ARGUMENT;
SQL_REWRITE_LOG(WARN, "other should not be null");
} else if (OB_UNLIKELY(!is_normal_key() || !other->is_normal_key()) ||
OB_UNLIKELY(pos_ != other->pos_)) {
ret = OB_INVALID_ARGUMENT;
SQL_REWRITE_LOG(WARN, "ObKeyPart not equal", K(*this), K(*other));
} else {
//bug:
ObObj &s1 = normal_keypart_->start_;
ObObj &e1 = normal_keypart_->end_;
ObObj &s2 = other->normal_keypart_->start_;
ObObj &e2 = other->normal_keypart_->end_;
if ((is_phy_rowid_key_part() && !other->is_phy_rowid_key_part()) ||
(!is_phy_rowid_key_part() && other->is_phy_rowid_key_part())) {
if (other->is_phy_rowid_key_part()) {
normal_keypart_->start_ = other->normal_keypart_->start_;
normal_keypart_->end_ = other->normal_keypart_->end_;
normal_keypart_->include_start_ = other->normal_keypart_->include_start_;
normal_keypart_->include_end_ = other->normal_keypart_->include_end_;
is_phy_rowid_key_part_ = true;
} else {/*do nothing*/}
} else if (!has_intersect(other)) {
// update this
normal_keypart_->start_.set_max_value();
normal_keypart_->end_.set_min_value();
normal_keypart_->include_start_ = false;
normal_keypart_->include_end_ = false;
normal_keypart_->always_false_ = true;
} else {
ObObj *s1 = &(normal_keypart_->start_);
ObObj *e1 = &(normal_keypart_->end_);
bool s1_flag = normal_keypart_->include_start_;
bool e1_flag = normal_keypart_->include_end_;
ObObj *s2 = &(other->normal_keypart_->start_);
bool s2_flag = other->normal_keypart_->include_start_;
ObObj *e2 = &(other->normal_keypart_->end_);
bool e2_flag = other->normal_keypart_->include_end_;
int cmp = 0;
SQL_REWRITE_LOG(DEBUG, "has intersect", KPC(this), KPC(other));
//取大
cmp = s1->compare(*s2);
if (cmp > 0) {
// do nothing
} else if (cmp < 0) {
s1 = s2;
s1_flag = s2_flag;
} else {
s1_flag = (s1_flag && s2_flag);
}
if (s1->is_null() && s1_flag) {
null_safe_ = null_safe_ && other->null_safe_;
}
// 取小
cmp = e1->compare(*e2);
if (cmp > 0) {
e1 = e2;
e1_flag = e2_flag;
} else if (cmp < 0) {
// do nothing
} else {
e1_flag = (e1_flag && e2_flag);
}
if (e1->is_null() && e1_flag) {
null_safe_ = null_safe_ && other->null_safe_;
}
// we need to set the always_true[false] flag accordingly to the intersection
if (s1 == &normal_keypart_->start_ && e1 == &normal_keypart_->end_) {
// do thing
} else if (s1 == &other->normal_keypart_->start_ && e1 == &other->normal_keypart_->end_) {
normal_keypart_->always_true_ = other->normal_keypart_->always_true_;
normal_keypart_->always_false_ = other->normal_keypart_->always_false_;
} else {
normal_keypart_->always_true_ = false;
normal_keypart_->always_false_ = false;
}
//set data
if (s1 != &normal_keypart_->start_) {
normal_keypart_->start_ = *s1;
}
if (e1 != &normal_keypart_->end_) {
normal_keypart_->end_ = *e1;
}
normal_keypart_->include_start_ = s1_flag;
normal_keypart_->include_end_ = e1_flag;
}
}
return ret;
}
int ObKeyPart::intersect_in(ObKeyPart *other)
{
int ret = OB_SUCCESS;
InParamMeta *param_meta = NULL;
ObSEArray<int64_t, 16> removed_val_idx;
if (OB_ISNULL(other) || OB_UNLIKELY(!is_in_key()) ||
OB_UNLIKELY(!other->is_normal_key() || other->is_phy_rowid_key_part_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(*other));
} else if (OB_UNLIKELY(!in_keypart_->find_param(other->pos_.offset_, param_meta))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to find param", K(ret), K(*other), K(*this));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < param_meta->vals_.count(); ++i) {
const ObObj &s1 = param_meta->vals_.at(i);
const ObObj &e1 = param_meta->vals_.at(i);
ObObj &s2 = other->normal_keypart_->start_;
ObObj &e2 = other->normal_keypart_->end_;
bool b_has_intersect = true;
bool s2_flag = other->normal_keypart_->include_start_;
bool e2_flag = other->normal_keypart_->include_end_;
int cmp_s2_e1 = 0;
int cmp_e2_s1 = 0;
if ((cmp_s2_e1 = s2.compare(e1)) > 0 || (cmp_e2_s1 = e2.compare(s1)) < 0
|| (0 == cmp_s2_e1 && false == s2_flag)
|| (0 == cmp_e2_s1 && false == e2_flag)) {
b_has_intersect = false;
}
if (!b_has_intersect && OB_FAIL(removed_val_idx.push_back(i))) {
LOG_WARN("failed to push back false value index", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(other->convert_to_true_or_false(false))) {
LOG_WARN("failed to convert to false key part", K(ret));
} else if (OB_FAIL(remove_in_params_vals(removed_val_idx))) {
LOG_WARN("failed to adjust in param values", K(ret));
}
}
return ret;
}
// TODO: this func can be optimized by inner hash join algorithm
int ObKeyPart::intersect_two_in_keys(ObKeyPart *other, const ObIArray<int64_t> &common_offsets)
{
int ret = OB_SUCCESS;
SameValIdxMap lr_idx;
if (OB_ISNULL(other) || OB_UNLIKELY(common_offsets.empty()) ||
(OB_UNLIKELY(!is_in_key() || !other->is_in_key()))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("get invalid argument", K(other), K(common_offsets.count()));
} else if (OB_FAIL(lr_idx.create(
hash::cal_next_prime(in_keypart_->in_params_.at(0)->vals_.count()), // no need to check params
"SameValMap", "SameValMap"))) {
LOG_WARN("failed to init hash map", K(ret));
} else {
bool is_valid = true;
for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < common_offsets.count(); ++i) {
InParamMeta *left_param = NULL;
InParamMeta *right_param = NULL;
if (!in_keypart_->find_param(common_offsets.at(i), left_param) ||
!other->in_keypart_->find_param(common_offsets.at(i), right_param)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to find param", K(ret), K(common_offsets), K(*this), K(*other));
} else if (OB_FAIL(collect_same_val_idxs(i == 0, left_param, right_param, lr_idx))) {
LOG_WARN("failed to collect sam value indexs", K(ret));
} else {
is_valid = (lr_idx.size() != 0);
}
}
if (OB_FAIL(ret)) {
} else if (!is_valid) {
if (OB_FAIL(convert_to_true_or_false(false))) {
LOG_WARN("failed to convert to always false", K(ret));
}
} else if (OB_FAIL(merge_two_in_keys(other, lr_idx))) {
LOG_WARN("failed to merge two in keys", K(ret));
}
}
return ret;
}
int ObKeyPart::collect_same_val_idxs(const bool is_first_offset,
const InParamMeta *left_param,
const InParamMeta *right_param,
SameValIdxMap &lr_idx)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(left_param) || OB_ISNULL(right_param)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < left_param->vals_.count(); ++i) {
ObSEArray<int64_t, 16> r_same_val_idx;
for (int64_t j = 0; OB_SUCC(ret) && j < right_param->vals_.count(); ++j) {
if (left_param->vals_.at(i).compare(right_param->vals_.at(j)) == 0) {
if (OB_FAIL(r_same_val_idx.push_back(j))) {
LOG_WARN("failed to push back same value idx", K(ret));
}
}
}
ObSEArray<int64_t, 16> existed_idx;
if (OB_FAIL(ret)) {
// do nothing
} else if (is_first_offset && r_same_val_idx.empty()) {
// do nothing
} else if (is_first_offset && !r_same_val_idx.empty()) {
if (OB_FAIL(lr_idx.set_refactored(i, r_same_val_idx))) {
LOG_WARN("failed to set refactored", K(ret));
}
} else if (!is_first_offset && r_same_val_idx.empty()) {
if (OB_FAIL(lr_idx.erase_refactored(i))) {
if (OB_HASH_NOT_EXIST == ret) {
ret = OB_SUCCESS;
} else {
LOG_WARN("failed to remove index", K(ret));
}
}
} else if (OB_FAIL(lr_idx.get_refactored(i, existed_idx))) {
if (OB_HASH_NOT_EXIST == ret) {
ret = OB_SUCCESS;
} else {
LOG_WARN("failed to get index", K(ret));
}
} else {
ObSEArray<int64_t, 16> common_idx;
if (OB_FAIL(ObOptimizerUtil::intersect(r_same_val_idx, existed_idx, common_idx))) {
LOG_WARN("failed to intersect index", K(ret));
} else if (common_idx.empty()) {
if (OB_FAIL(lr_idx.erase_refactored(i))) {
LOG_WARN("failed to remove index", K(ret));
}
} else if (OB_FAIL(lr_idx.set_refactored(i, common_idx, 1))) {
LOG_WARN("failed to set idx", K(ret));
}
}
}
}
return ret;
}
int ObKeyPart::merge_two_in_keys(ObKeyPart *other, const SameValIdxMap &lr_idx)
{
int ret = OB_SUCCESS;
ObSEArray<InParamMeta *, 4> new_params;
if (OB_ISNULL(other) || OB_UNLIKELY(!other->is_in_key()) || OB_UNLIKELY(!is_in_key())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(other), K(key_type_));
} else if (OB_FAIL(append_array_no_dup(in_keypart_->offsets_,
other->in_keypart_->offsets_))) {
LOG_WARN("failed to append right offsets", K(ret));
} else {
int64_t offsets_cnt = in_keypart_->offsets_.count();
// std::sort(left_in->in_keypart_->offsets_.begin(), left_in->in_keypart_->offsets_.end());
for (int64_t i = 0; OB_SUCC(ret) && i < offsets_cnt; ++i) {
InParamMeta *cur_param = NULL;
InParamMeta *new_param = NULL;
ObSEArray<ObObj, 4> vals;
if (OB_ISNULL(new_param = in_keypart_->create_param_meta(allocator_))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate param", K(ret));
} else if (in_keypart_->find_param(in_keypart_->offsets_.at(i), cur_param)) {
for (auto it = lr_idx.begin(); OB_SUCC(ret) && it != lr_idx.end(); ++it) {
int64_t val_idx = it->first;
int64_t copy_cnt = it->second.count();
if (OB_UNLIKELY(val_idx < 0 || val_idx >= cur_param->vals_.count())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid value idx", K(ret));
} else {
const ObObj &val = cur_param->vals_.at(val_idx);
for (int64_t j = 0; OB_SUCC(ret) && j < copy_cnt; ++j) {
ObObj copied_val;
if (OB_FAIL(ob_write_obj(allocator_, val, copied_val))) {
LOG_WARN("failed to copy obj", K(ret));
} else if (OB_FAIL(vals.push_back(copied_val))) {
LOG_WARN("failed to push back val", K(ret));
}
}
}
}
} else if (other->in_keypart_->find_param(in_keypart_->offsets_.at(i), cur_param)) {
for (auto it = lr_idx.begin(); OB_SUCC(ret) && it != lr_idx.end(); ++it) {
int64_t val_idx = it->first;
const ObSEArray<int64_t, 16> &r_val_idx = it->second;
for (int64_t j = 0; OB_SUCC(ret) && j < r_val_idx.count(); ++j) {
if (OB_FAIL(vals.push_back(cur_param->vals_.at(r_val_idx.at(j))))) {
LOG_WARN("failed to push back val", K(ret));
}
}
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("can't find param", K(ret));
}
if (OB_SUCC(ret)) {
new_param->pos_ = cur_param->pos_;
if (OB_FAIL(new_param->vals_.assign(vals))) {
LOG_WARN("failed to assign vals", K(ret), K(vals.count()));
} else if (OB_FAIL(new_params.push_back(new_param))) {
LOG_WARN("failed to push back new param", K(ret));
}
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(in_keypart_->in_params_.assign(new_params))) {
LOG_WARN("failed to assign new params", K(ret));
} else if (OB_FAIL(formalize_keypart(false))) {
LOG_WARN("failed to formalize key part", K(ret));
}
}
return ret;
}
/*
* 整个链都可以表示成and,没有多余的东西
* (A or B) and C general_or_next is null
* (A and C) or (B and C) general_or_next is NULL or (B and C) ?
* (A and B) or C general_or_next is C
*/
ObKeyPart *ObKeyPart::general_or_next()
{
ObKeyPart *gt_or = or_next_;
while (NULL != gt_or && gt_or->and_next_ == and_next_) {
gt_or = gt_or->or_next_;
}
return gt_or;
}
ObKeyPart *ObKeyPart::cut_general_or_next()
{
ObKeyPart *prev_or = this;
ObKeyPart *gt_or = or_next_;
while (NULL != gt_or && gt_or->and_next_ == and_next_) {
prev_or = gt_or;
gt_or = gt_or->or_next_;
}
prev_or->or_next_ = NULL;
return gt_or;
}
/**
* @brief
* (A1 or A2 or A3) and B (A1 and B) or (A2 and B) or (A3 and B)
* graph: link gt:
* or or or or
* A1---->A2---->A3 A1---->A2---->A3
*and | and | and | and |
* B B B B
* @param and_next
*/
void ObKeyPart::link_gt(ObKeyPart *and_next)
{
ObKeyPart *cur = this;
while (NULL != cur) {
cur->and_next_ = and_next;
cur = cur->or_next_;
}
}
int ObKeyPart::deep_node_copy(const ObKeyPart &other)
{
int ret = OB_SUCCESS;
id_ = other.id_;
pos_ = other.pos_;
null_safe_ = other.null_safe_;
rowid_column_idx_ = other.rowid_column_idx_;
is_phy_rowid_key_part_ = other.is_phy_rowid_key_part_;
item_next_ = NULL;
or_next_ = NULL;
and_next_ = NULL;
if (other.is_normal_key()) {
if (OB_FAIL(create_normal_key())) {
LOG_WARN("create normal key failed", K(ret));
} else if (OB_FAIL(ob_write_obj(allocator_, other.normal_keypart_->start_, normal_keypart_->start_))) {
LOG_WARN("deep copy start obj failed", K(ret));
} else if (OB_FAIL(ob_write_obj(allocator_, other.normal_keypart_->end_, normal_keypart_->end_))) {
LOG_WARN("deep copy end obj failed", K(ret));
} else {
normal_keypart_->always_false_ = other.normal_keypart_->always_false_;
normal_keypart_->always_true_ = other.normal_keypart_->always_true_;
normal_keypart_->include_start_ = other.normal_keypart_->include_start_;
normal_keypart_->include_end_ = other.normal_keypart_->include_end_;
}
} else if (other.is_like_key()) {
if (OB_FAIL(create_like_key())) {
LOG_WARN("create like key failed", K(ret));
} else if (OB_FAIL(ob_write_obj(allocator_, other.like_keypart_->pattern_, like_keypart_->pattern_))) {
LOG_WARN("deep copy like pattern failed", K(ret));
} else if (OB_FAIL(ob_write_obj(allocator_, other.like_keypart_->escape_, like_keypart_->escape_))) {
LOG_WARN("deep copy like escape failed", K(ret));
}
} else if (other.is_in_key()) {
if (OB_FAIL(create_in_key())) {
LOG_WARN("create in key failed", K(ret));
} else if (OB_FAIL(in_keypart_->offsets_.assign(other.in_keypart_->offsets_))) {
LOG_WARN("failed to assign key offsets", K(ret));
} else if (OB_FAIL(in_keypart_->missing_offsets_.assign(other.in_keypart_->missing_offsets_))) {
LOG_WARN("failed to assign key missing offsets", K(ret));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < other.in_keypart_->in_params_.count(); ++i) {
InParamMeta *param = other.in_keypart_->in_params_.at(i);
InParamMeta *new_param = NULL;
if (OB_ISNULL(new_param = in_keypart_->create_param_meta(allocator_))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate param meta", K(ret));
} else if (OB_FAIL(new_param->assign(*param, allocator_))) {
LOG_WARN("failed to assign new param", K(ret));
} else if (OB_FAIL(in_keypart_->in_params_.push_back(new_param))) {
LOG_WARN("failed to push back new param", K(ret));
}
}
in_keypart_->table_id_ = other.in_keypart_->table_id_;
in_keypart_->in_type_ = other.in_keypart_->in_type_;
in_keypart_->is_strict_in_ = other.in_keypart_->is_strict_in_;
in_keypart_->contain_questionmark_ = other.in_keypart_->contain_questionmark_;
}
} else if (other.is_geo_key()) {
if (OB_FAIL(create_geo_key())) {
LOG_WARN("create geo key failed", K(ret));
} else if (OB_FAIL(ob_write_obj(allocator_, other.geo_keypart_->wkb_, geo_keypart_->wkb_))) {
LOG_WARN("deep copy geo wkb failed", K(ret));
} else if (OB_FAIL(ob_write_obj(allocator_, other.geo_keypart_->distance_, geo_keypart_->distance_))) {
LOG_WARN("deep copy geo distance failed", K(ret));
} else {
geo_keypart_->geo_type_ = other.geo_keypart_->geo_type_;
}
}
return ret;
}
int ObKeyPart::shallow_node_copy(const ObKeyPart &other)
{
int ret = OB_SUCCESS;
reset_key();
id_ = other.id_;
pos_ = other.pos_;
null_safe_ = other.null_safe_;
rowid_column_idx_ = other.rowid_column_idx_;
is_phy_rowid_key_part_ = other.is_phy_rowid_key_part_;
if (other.is_normal_key()) {
normal_keypart_ = other.normal_keypart_;
key_type_ = other.key_type_;
} else if (other.is_like_key()) {
like_keypart_ = other.like_keypart_;
key_type_ = other.key_type_;
} else if (other.is_in_key()) {
in_keypart_ = other.in_keypart_;
key_type_ = other.key_type_;
} else if (other.is_geo_key()) {
geo_keypart_ = other.geo_keypart_;
key_type_ = other.key_type_;
}
return ret;
}
int InParamMeta::assign(const InParamMeta &other, ObIAllocator &alloc)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(other.vals_.empty())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid in keypart", K(ret));
} else if (OB_FAIL(pos_.assign(other.pos_))) {
LOG_WARN("failed to assign other", K(ret));
} else if (OB_FAIL(vals_.reserve(other.vals_.count()))) {
LOG_WARN("failed to reserve vals count", K(ret));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < other.vals_.count(); ++i) {
ObObj new_val;
if (OB_FAIL(ob_write_obj(alloc, other.vals_.at(i), new_val))) {
LOG_WARN("failed to copy obj", K(ret));
} else if (OB_FAIL(vals_.push_back(new_val))) {
LOG_WARN("failed to push back new val", K(ret));
}
}
}
return ret;
}
InParamMeta* ObInKeyPart::create_param_meta(ObIAllocator &alloc)
{
void *ptr = NULL;
InParamMeta *new_param = NULL;
if (OB_NOT_NULL(ptr = alloc.alloc(sizeof(InParamMeta)))) {
new_param = new(ptr) InParamMeta();
new_param->vals_.set_block_allocator(ModulePageAllocator(alloc));
new_param->pos_.enum_set_values_.set_block_allocator(ModulePageAllocator(alloc));
}
return new_param;
}
int64_t ObInKeyPart::get_valid_offset_cnt(int64_t max_valid_off) const
{
int64_t valid_off_cnt = 0;
for (int64_t i = 0; i < offsets_.count(); ++i) {
if (offsets_.at(i) <= max_valid_off) {
++valid_off_cnt;
} else {
break;
}
}
return valid_off_cnt;
}
bool ObInKeyPart::find_param(const int64_t offset, InParamMeta *&param_meta)
{
bool found = false;
param_meta = NULL;
for (int64_t i = 0; !found && i < in_params_.count(); ++i) {
if (in_params_.at(i)->pos_.offset_ == offset) {
param_meta = in_params_.at(i);
found = true;
}
}
return found;
}
bool ObInKeyPart::offsets_same_to(const ObInKeyPart *other) const
{
bool bret = true;
if (OB_ISNULL(other) || offsets_.count() != other->offsets_.count()) {
bret = false;
} else {
for (int64_t i = 0; i < offsets_.count(); ++i) {
if (offsets_.at(i) != other->offsets_.at(i)) {
bret = false;
}
}
}
return bret;
}
int ObInKeyPart::union_in_key(ObInKeyPart *other)
{
int ret = OB_SUCCESS;
if (!offsets_same_to(other)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("only in key with same offsets can be unioned", K(ret));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < in_params_.count(); ++i) {
InParamMeta *cur_param = in_params_.at(i);
InParamMeta *other_param = other->in_params_.at(i);
if (OB_UNLIKELY(cur_param->pos_ != other_param->pos_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid argument", K(ret), K(*cur_param), K(*other_param));
} else if (OB_FAIL(append(cur_param->vals_, other_param->vals_))) {
LOG_WARN("failed to append array no dup", K(ret));
}
}
}
return ret;
}
int ObInKeyPart::get_dup_vals(int64_t offset, const ObObj &val, ObIArray<int64_t> &dup_val_idx)
{
int ret = OB_SUCCESS;
InParamMeta *param_meta = NULL;
if (!find_param(offset, param_meta)) {
// do nothing
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < param_meta->vals_.count(); ++i) {
if (param_meta->vals_.at(i).compare(val) == 0) {
ret = dup_val_idx.push_back(i);
}
}
}
return ret;
}
int ObInKeyPart::remove_in_dup_vals()
{
int ret = OB_SUCCESS;
int param_cnt = in_params_.count();
int val_cnt = get_param_val_cnt();
common::hash::ObHashSet<InParamValsWrapper> distinct_param_val_set;
ObSEArray<InParamValsWrapper, 16> distinct_param_val_arr;
ObSEArray<obj_cmp_func, MAX_EXTRACT_IN_COLUMN_NUMBER> cmp_funcs;
if (OB_UNLIKELY(param_cnt == 0 || val_cnt == 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid in keypart", K(ret), K(param_cnt), K(val_cnt));
} else if (OB_FAIL(distinct_param_val_set.create(val_cnt))) {
LOG_WARN("failed to create partition macro id set", K(ret));
} else if (OB_FAIL(get_obj_cmp_funcs(cmp_funcs))) {
LOG_WARN("failed to get cmp funcs", K(ret));
}
bool has_dup = false;
for (int64_t i = 0; OB_SUCC(ret) && i < val_cnt; ++i) {
InParamValsWrapper cur_param_vals;
for (int64_t j = 0; OB_SUCC(ret) && j < param_cnt; ++j) {
InParamMeta *cur_param = in_params_.at(j);
if (OB_ISNULL(cur_param) || OB_UNLIKELY(val_cnt != cur_param->vals_.count())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid argument", K(ret), K(val_cnt), K(cur_param), K(i), K(j));
} else if (OB_FAIL(cur_param_vals.param_vals_.push_back(cur_param->vals_.at(i)))) {
LOG_WARN("failed to push back val", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(cur_param_vals.cmp_funcs_.assign(cmp_funcs))) {
LOG_WARN("failed to assign cmp func", K(ret));
} else if (OB_HASH_EXIST == (ret = distinct_param_val_set.set_refactored(cur_param_vals, 0))) {
ret = OB_SUCCESS;
has_dup = true;
} else if (OB_UNLIKELY(OB_SUCCESS != ret)) {
LOG_WARN("failed to set range", K(ret));
} else if (OB_FAIL(distinct_param_val_arr.push_back(cur_param_vals))) {
LOG_WARN("failed to push back param values", K(ret));
}
}
if (OB_SUCC(ret) && has_dup) {
for (int64_t i = 0; OB_SUCC(ret) && i < param_cnt; ++i) {
in_params_.at(i)->vals_.reuse();
}
for (int64_t i = 0; OB_SUCC(ret) && i < distinct_param_val_arr.count(); ++i) {
const InParamValsWrapper &cur_param_vals = distinct_param_val_arr.at(i);
if (OB_UNLIKELY(cur_param_vals.param_vals_.count() != param_cnt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid param cnt", K(ret), K(param_cnt), K(cur_param_vals.param_vals_.count()));
} else {
for (int64_t j = 0; OB_SUCC(ret) && j < param_cnt; ++j) {
if (OB_ISNULL(in_params_.at(j))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(in_params_.at(j)->vals_.push_back(cur_param_vals.param_vals_.at(j)))) {
LOG_WARN("failed to push back val", K(ret));
}
}
}
}
}
LOG_TRACE("succeed to remove duplicated values from in keypart", K(has_dup), K(val_cnt), K(distinct_param_val_arr.count()));
return ret;
}
int ObInKeyPart::get_obj_cmp_funcs(ObIArray<obj_cmp_func> &cmp_funcs)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < in_params_.count(); ++i) {
InParamMeta *cur_param = in_params_.at(i);
obj_cmp_func cmp_op_func = NULL;
if (OB_ISNULL(cur_param) || OB_UNLIKELY(cur_param->vals_.count() == 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid argument", K(ret), K(cur_param), K(i));
} else {
const ObObjTypeClass obj_tc = cur_param->vals_.at(0).get_meta().get_type_class();
if (OB_FAIL(ObObjCmpFuncs::get_cmp_func(obj_tc, obj_tc, CO_EQ, cmp_op_func))) {
LOG_WARN("failed to get cmp func", K(ret), K(obj_tc));
} else {
OB_ASSERT(cmp_op_func != NULL);
ret = cmp_funcs.push_back(cmp_op_func);
}
}
}
return ret;
}
// TODO: can be optimized by hash join algorithm, see ObKeyPart::intersect_two_in_keys
int ObKeyPart::union_in_dup_vals(ObKeyPart *other, bool &is_unioned)
{
int ret = OB_SUCCESS;
InParamMeta *cur_param = NULL;
is_unioned = false;
if (OB_ISNULL(other) || OB_UNLIKELY(!is_in_key() || !other->is_in_key())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(other));
} else if (!in_keypart_->find_param(other->in_keypart_->get_min_offset(), cur_param)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to find param", K(ret), K(*other), K(*this));
} else {
ObSEArray<int64_t, 16> dup_val_idx;
int64_t in_param_cnt = in_keypart_->in_params_.count();
int64_t other_in_param_cnt = other->in_keypart_->in_params_.count();
for (int64_t i = 0; OB_SUCC(ret) && i < cur_param->vals_.count(); ++i) {
bool is_all_same = true;
int64_t idx = 0;
ObSEArray<int64_t, 16> other_dup_val_idx;
for (; OB_SUCC(ret) && is_all_same &&
idx < in_param_cnt && idx < other_in_param_cnt; ++idx) {
cur_param = in_keypart_->in_params_.at(idx);
ObSEArray<int64_t, 16> tmp_other_dup_val_idx;
ObSEArray<int64_t, 16> common_idx;
if (OB_FAIL(other->in_keypart_->get_dup_vals(cur_param->pos_.offset_,
cur_param->vals_.at(i),
tmp_other_dup_val_idx))) {
LOG_WARN("failed to get duplicate values", K(ret));
} else if (tmp_other_dup_val_idx.empty()) {
is_all_same = false;
} else if (other_dup_val_idx.empty()) {
ret = other_dup_val_idx.assign(tmp_other_dup_val_idx);
} else if (OB_FAIL(ObOptimizerUtil::intersect(tmp_other_dup_val_idx,
other_dup_val_idx,
common_idx))) {
LOG_WARN("failed to intersect index", K(ret));
} else if (common_idx.empty()) {
is_all_same = false;
} else if (OB_FAIL(other_dup_val_idx.assign(common_idx))) {
LOG_WARN("failed to set idx", K(ret));
}
}
if (OB_SUCC(ret) && is_all_same) {
is_unioned = true;
if (idx < other_in_param_cnt) {
// c1 in or (c1, c2) in
if (OB_FAIL(other->remove_in_params_vals(other_dup_val_idx))) {
LOG_WARN("failed to remove in param values", K(ret));
} else if (other->is_always_false()) {
break;
}
} else {
// (c1, c2) in or c1 in
// (c1, c2) in or (c1, c2) in
ret = dup_val_idx.push_back(i);
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(remove_in_params_vals(dup_val_idx))) {
LOG_WARN("failed to remove in param vals", K(ret));
}
}
}
return ret;
}
OB_SERIALIZE_MEMBER(ObKeyPartId, table_id_, column_id_);
OB_SERIALIZE_MEMBER(ObKeyPartPos, offset_, column_type_, enum_set_values_);
int ObKeyPartPos::set_enum_set_values(common::ObIAllocator &allocator,
const common::ObIArray<common::ObString> &enum_set_values)
{
int ret = OB_SUCCESS;
ObString value;
enum_set_values_.set_block_allocator(ModulePageAllocator(allocator));
for (int64_t i = 0; OB_SUCC(ret) && i < enum_set_values.count(); ++i) {
value.reset();
if (OB_FAIL(ob_write_string(allocator, enum_set_values.at(i), value))) {
LOG_WARN("fail to copy obstring", K(enum_set_values), K(value), K(ret));
} else if (OB_FAIL(enum_set_values_.push_back(value))){
LOG_WARN("fail to push back value", K(enum_set_values), K(value), K(ret));
}
}
return ret;
}
int ObKeyPartPos::assign(const ObKeyPartPos &other)
{
int ret = OB_SUCCESS;
offset_ = other.offset_;
column_type_ = other.column_type_;
if (OB_FAIL(enum_set_values_.assign(other.enum_set_values_))) {
LOG_WARN("failed to assign enum set values", K(ret));
}
return ret;
}
OB_DEF_SERIALIZE(ObKeyPart)
{
int ret = OB_SUCCESS;
OB_UNIS_ENCODE(id_);
OB_UNIS_ENCODE(pos_);
OB_UNIS_ENCODE(static_cast<int64_t>(key_type_));
if (OB_SUCC(ret)) {
if (is_normal_key()) {
OB_UNIS_ENCODE(normal_keypart_->start_);
OB_UNIS_ENCODE(normal_keypart_->include_start_);
OB_UNIS_ENCODE(normal_keypart_->end_);
OB_UNIS_ENCODE(normal_keypart_->include_end_);
OB_UNIS_ENCODE(normal_keypart_->always_true_);
OB_UNIS_ENCODE(normal_keypart_->always_false_);
} else if (is_like_key()) {
OB_UNIS_ENCODE(like_keypart_->pattern_);
OB_UNIS_ENCODE(like_keypart_->escape_);
} else if (is_in_key()) {
int64_t param_cnt = in_keypart_->in_params_.count();
int64_t val_cnt = in_keypart_->get_param_val_cnt();
OB_UNIS_ENCODE(in_keypart_->table_id_);
OB_UNIS_ENCODE(in_keypart_->in_type_);
OB_UNIS_ENCODE(in_keypart_->contain_questionmark_);
OB_UNIS_ENCODE(in_keypart_->is_strict_in_);
OB_UNIS_ENCODE(in_keypart_->offsets_);
OB_UNIS_ENCODE(in_keypart_->missing_offsets_);
OB_UNIS_ENCODE(param_cnt);
OB_UNIS_ENCODE(val_cnt);
for (int64_t i = 0; OB_SUCC(ret) && i < param_cnt; ++i) {
InParamMeta *param_meta = in_keypart_->in_params_.at(i);
if (OB_ISNULL(param_meta)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else {
OB_UNIS_ENCODE(param_meta->pos_);
for (int64_t j = 0; OB_SUCC(ret) && j < val_cnt; ++j) {
OB_UNIS_ENCODE(param_meta->vals_.at(j));
}
}
}
} else if (is_geo_key()) {
OB_UNIS_ENCODE(geo_keypart_->wkb_);
OB_UNIS_ENCODE(geo_keypart_->geo_type_);
OB_UNIS_ENCODE(geo_keypart_->distance_);
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected key type", K_(key_type));
}
}
OB_UNIS_ENCODE(null_safe_);
OB_UNIS_ENCODE(rowid_column_idx_);
OB_UNIS_ENCODE(is_phy_rowid_key_part_);
return ret;
}
OB_DEF_DESERIALIZE(ObKeyPart)
{
int ret = OB_SUCCESS;
//要做到向前兼容,因为null_safe的范围比范围比not null safe的范围更大,对于老版本没有去filter的plan
//宁愿range变得更大,不能接受range被缩小,所以这里将null_safe_初始化为true
null_safe_ = true;
OB_UNIS_DECODE(id_);
OB_UNIS_DECODE(pos_);
OB_UNIS_DECODE(key_type_);
if (OB_SUCC(ret)) {
if (T_NORMAL_KEY == key_type_) {
if (OB_FAIL(create_normal_key())) {
LOG_WARN("create normal key failed", K(ret));
}
OB_UNIS_DECODE(normal_keypart_->start_);
OB_UNIS_DECODE(normal_keypart_->include_start_);
OB_UNIS_DECODE(normal_keypart_->end_);
OB_UNIS_DECODE(normal_keypart_->include_end_);
OB_UNIS_DECODE(normal_keypart_->always_true_);
OB_UNIS_DECODE(normal_keypart_->always_false_);
} else if (T_LIKE_KEY == key_type_) {
if (OB_FAIL(create_like_key())) {
LOG_WARN("create like key failed", K(ret));
}
OB_UNIS_DECODE(like_keypart_->pattern_);
OB_UNIS_DECODE(like_keypart_->escape_);
} else if (T_IN_KEY == key_type_) {
if (OB_FAIL(create_in_key())) {
LOG_WARN("create in key failed", K(ret));
}
int64_t param_cnt = 0;
int64_t val_cnt = 0;
OB_UNIS_DECODE(in_keypart_->table_id_);
OB_UNIS_DECODE(in_keypart_->in_type_);
OB_UNIS_DECODE(in_keypart_->contain_questionmark_);
OB_UNIS_DECODE(in_keypart_->is_strict_in_);
OB_UNIS_DECODE(in_keypart_->offsets_);
OB_UNIS_DECODE(in_keypart_->missing_offsets_);
OB_UNIS_DECODE(param_cnt);
OB_UNIS_DECODE(val_cnt);
for (int64_t i = 0; OB_SUCC(ret) && i < param_cnt; ++i) {
InParamMeta *param_meta = NULL;
ObKeyPartPos key_pos;
OB_UNIS_DECODE(key_pos);
if (OB_ISNULL(param_meta = in_keypart_->create_param_meta(allocator_))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("callocate memory failed", K(ret));
} else {
param_meta->pos_ = key_pos;
for (int64_t j = 0; OB_SUCC(ret) && j < val_cnt; ++j) {
ObObj val;
OB_UNIS_DECODE(val);
if (OB_FAIL(param_meta->vals_.push_back(val))) {
LOG_WARN("failed to push back val", K(ret));
}
}
if (OB_SUCC(ret) &&
OB_FAIL(in_keypart_->in_params_.push_back(param_meta))) {
LOG_WARN("failed to push back param meta", K(ret));
}
}
}
} else if (T_GEO_KEY == key_type_) {
if (OB_FAIL(create_geo_key())) {
LOG_WARN("create geo key failed", K(ret));
}
OB_UNIS_DECODE(geo_keypart_->wkb_);
OB_UNIS_DECODE(geo_keypart_->geo_type_);
OB_UNIS_DECODE(geo_keypart_->distance_);
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected key type", K_(key_type));
}
}
OB_UNIS_DECODE(null_safe_);
OB_UNIS_DECODE(rowid_column_idx_);
OB_UNIS_DECODE(is_phy_rowid_key_part_);
return ret;
}
OB_DEF_SERIALIZE_SIZE(ObKeyPart)
{
int64_t len = 0;
OB_UNIS_ADD_LEN(id_);
OB_UNIS_ADD_LEN(pos_);
OB_UNIS_ADD_LEN(static_cast<int64_t>(key_type_));
if (is_normal_key()) {
OB_UNIS_ADD_LEN(normal_keypart_->start_);
OB_UNIS_ADD_LEN(normal_keypart_->include_start_);
OB_UNIS_ADD_LEN(normal_keypart_->end_);
OB_UNIS_ADD_LEN(normal_keypart_->include_end_);
OB_UNIS_ADD_LEN(normal_keypart_->always_true_);
OB_UNIS_ADD_LEN(normal_keypart_->always_false_);
} else if (is_like_key()) {
OB_UNIS_ADD_LEN(like_keypart_->pattern_);
OB_UNIS_ADD_LEN(like_keypart_->escape_);
} else if (is_in_key()) {
int64_t param_cnt = in_keypart_->in_params_.count();
int64_t val_cnt = in_keypart_->get_param_val_cnt();
OB_UNIS_ADD_LEN(in_keypart_->table_id_);
OB_UNIS_ADD_LEN(in_keypart_->in_type_);
OB_UNIS_ADD_LEN(in_keypart_->contain_questionmark_);
OB_UNIS_ADD_LEN(in_keypart_->is_strict_in_);
OB_UNIS_ADD_LEN(in_keypart_->offsets_);
OB_UNIS_ADD_LEN(in_keypart_->missing_offsets_);
OB_UNIS_ADD_LEN(param_cnt);
OB_UNIS_ADD_LEN(val_cnt);
for (int64_t i = 0; i < param_cnt; ++i) {
InParamMeta *param_meta = in_keypart_->in_params_.at(i);
if (OB_ISNULL(param_meta)) {
// do nothing
} else {
OB_UNIS_ADD_LEN(param_meta->pos_);
for (int64_t j = 0; j < val_cnt; ++j) {
OB_UNIS_ADD_LEN(param_meta->vals_.at(j));
}
}
}
} else if (is_geo_key()) {
OB_UNIS_ADD_LEN(geo_keypart_->wkb_);
OB_UNIS_ADD_LEN(geo_keypart_->geo_type_);
OB_UNIS_ADD_LEN(geo_keypart_->distance_);
}
OB_UNIS_ADD_LEN(null_safe_);
OB_UNIS_ADD_LEN(rowid_column_idx_);
OB_UNIS_ADD_LEN(is_phy_rowid_key_part_);
return len;
}
int ObKeyPart::formalize_keypart(bool contain_row)
{
int ret = OB_SUCCESS;
if (is_always_true() || is_always_false()) {
// do nothing
} else if (is_normal_key()) {
if (normal_keypart_->start_.is_min_value() && normal_keypart_->end_.is_max_value()) {
normal_keypart_->always_true_ = true;
} else if (!normal_keypart_->start_.can_compare(normal_keypart_->end_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("start obj can not compare with end obj",
"start", normal_keypart_->start_, "end", normal_keypart_->end_, K(ret));
} else {
int cmp = normal_keypart_->start_.compare(normal_keypart_->end_);
if ((cmp > 0) || (0 == cmp && (!normal_keypart_->include_start_ || !normal_keypart_->include_end_))) {
if (contain_row && pos_.offset_ > 0) {
normal_keypart_->always_false_ = false;
} else {
normal_keypart_->always_false_ = true;
}
} else {
normal_keypart_->always_true_ = false;
normal_keypart_->always_false_ = false;
}
}
} else if (is_in_key()) {
std::sort(in_keypart_->offsets_.begin(), in_keypart_->offsets_.end());
std::sort(in_keypart_->in_params_.begin(),
in_keypart_->in_params_.end(),
[] (const InParamMeta *e1, const InParamMeta *e2) {
return e1->pos_.offset_ <= e2->pos_.offset_;
});
int64_t off = -1;
in_keypart_->is_strict_in_ = true;
in_keypart_->missing_offsets_.reuse();
for (int64_t i = 0; OB_SUCC(ret) && i < in_keypart_->offsets_.count(); ++i) {
int64_t cur_off = in_keypart_->offsets_.at(i);
if (off == -1) {
off = cur_off;
} else if (off == cur_off) {
// duplicated
} else if (cur_off != ++off) {
in_keypart_->is_strict_in_ = false;
while (off < cur_off) {
ret = in_keypart_->missing_offsets_.push_back(off);
++off;
}
}
}
// merge duplicated key. eg: (c1, c1) in ((1,2),(2,2)) -> c1 in (2)
if (!in_keypart_->contain_questionmark_) {
ObSEArray<int64_t, 4> dup_param_idx;
ObSEArray<int64_t, 4> invalid_val_idx;
if (OB_FAIL(get_dup_param_and_vals(dup_param_idx, invalid_val_idx))) {
LOG_WARN("failed to get duplicated param and values", K(ret));
} else if (OB_FAIL(remove_in_params(dup_param_idx, false))) {
LOG_WARN("failed to adjust in param", K(ret));
} else if (OB_FAIL(remove_in_params_vals(invalid_val_idx))) {
LOG_WARN("failed to adjust in param values", K(ret));
} else if (OB_FAIL(remove_in_dup_vals())) {
LOG_WARN("failed to remove duplicated values", K(ret));
}
}
if (OB_SUCC(ret) && is_in_key() &&
(in_keypart_->in_params_.empty() || in_keypart_->get_param_val_cnt() == 0)) {
if (OB_FAIL(convert_to_true_or_false(false))) {
LOG_WARN("failed to convert to always true");
}
}
}
return ret;
}
int ObKeyPart::remove_in_dup_vals()
{
int ret = OB_SUCCESS;
if (!is_in_key()) {
} else if (OB_FAIL(in_keypart_->remove_in_dup_vals())) {
LOG_WARN("failed to remove in dup values", K(ret));
} else if (in_keypart_->get_param_val_cnt() == 0) {
ret = convert_to_true_or_false(false);
}
return ret;
}
int ObKeyPart::get_dup_param_and_vals(ObIArray<int64_t> &dup_param_idx, ObIArray<int64_t> &invalid_val_idx)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!is_in_key())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("get invalid argument", K(ret));
} else {
int64_t i = 0;
while (OB_SUCC(ret) && i < in_keypart_->offsets_.count() - 1) {
InParamMeta *start_param = in_keypart_->in_params_.at(i);
while (OB_SUCC(ret) && i < in_keypart_->offsets_.count() - 1 &&
in_keypart_->offsets_.at(i) == in_keypart_->offsets_.at(i + 1)) {
InParamMeta *next_param = in_keypart_->in_params_.at(i + 1);
if (OB_ISNULL(start_param) || OB_ISNULL(next_param)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(dup_param_idx.push_back(i + 1))) {
LOG_WARN("failed to push back removed param idx", K(ret));
} else {
for (int64_t j = 0; OB_SUCC(ret) && j < start_param->vals_.count(); ++j) {
if (OB_UNLIKELY(start_param->vals_.count() != next_param->vals_.count())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("values count must be the same", K(ret), K(*start_param), K(*next_param));
} else if (!is_contain(invalid_val_idx, j) &&
next_param->vals_.at(j) != start_param->vals_.at(j)) {
ret = invalid_val_idx.push_back(j);
}
}
}
++i;
}
++i;
}
}
return ret;
}
int ObKeyPart::remove_in_params(const ObIArray<int64_t> &invalid_param_idx, bool always_true)
{
int ret = OB_SUCCESS;
if (is_always_true() || is_always_false() || invalid_param_idx.empty()) {
// do nothing
} else if (OB_UNLIKELY(!is_in_key())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else {
ObSEArray<int64_t, 4> new_offsets;
ObSEArray<InParamMeta *, 4> new_params;
for (int64_t i = 0; OB_SUCC(ret) && i < in_keypart_->offsets_.count(); ++i) {
int64_t cur_offset = in_keypart_->offsets_.at(i);
InParamMeta *cur_param = in_keypart_->in_params_.at(i);
if (is_contain(invalid_param_idx, i)) {
// invalid, do nothing
} else if (OB_FAIL(new_offsets.push_back(cur_offset))) {
LOG_WARN("failed to push back offset", K(ret));
} else if (OB_FAIL(new_params.push_back(cur_param))) {
LOG_WARN("failed to push back new param", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_UNLIKELY(new_offsets.empty())) {
if (OB_FAIL(convert_to_true_or_false(always_true))) {
LOG_WARN("failed to convert to always false", K(ret));
}
} else if (OB_FAIL(in_keypart_->offsets_.assign(new_offsets))) {
LOG_WARN("failed to assign new offsets", K(ret));
} else if (OB_FAIL(in_keypart_->in_params_.assign(new_params))) {
LOG_WARN("failed to assign new params", K(ret));
}
}
return ret;
}
int ObKeyPart::remove_in_params_vals(const ObIArray<int64_t> &val_idx)
{
int ret = OB_SUCCESS;
if (is_always_true() || is_always_false() || val_idx.empty()) {
// do nothing
} else if (OB_UNLIKELY(!is_in_key())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("get unexpected null", K(ret));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < in_keypart_->in_params_.count(); ++i) {
InParamMeta *param_meta = in_keypart_->in_params_.at(i);
ObSEArray<ObObj, 128> new_vals;
for (int64_t j = 0; OB_SUCC(ret) && j < param_meta->vals_.count(); ++j) {
if (!is_contain(val_idx, j) &&
OB_FAIL(new_vals.push_back(param_meta->vals_.at(j)))) {
LOG_WARN("failed to push back val", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_UNLIKELY(new_vals.empty())) {
if (OB_FAIL(convert_to_true_or_false(false))) {
LOG_WARN("failed to convert to always false", K(ret));
} else {
break;
}
} else if (OB_FAIL(param_meta->vals_.assign(new_vals))) {
LOG_WARN("failed to assign new values", K(ret));
}
}
}
return ret;
}
int ObKeyPart::cast_value_type(const ObDataTypeCastParams &dtc_params, bool contain_row, bool &is_bound_modified)
{
int ret = OB_SUCCESS;
int64_t start_cmp = 0;
int64_t end_cmp = 0;
if (OB_UNLIKELY(!is_normal_key())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("keypart isn't normal key", K_(key_type));
} else if (OB_FAIL(ObKeyPart::try_cast_value(dtc_params, allocator_, pos_,
normal_keypart_->start_, start_cmp))) {
LOG_WARN("failed to try cast value type", K(ret));
} else if (OB_FAIL(ObKeyPart::try_cast_value(dtc_params, allocator_, pos_,
normal_keypart_->end_, end_cmp))) {
LOG_WARN("failed to try cast value type", K(ret));
} else {
if (start_cmp < 0) {
// after cast, precise becomes bigger, ( -> [
normal_keypart_->include_start_ = true;
is_bound_modified = true;
} else if (start_cmp > 0) {
// after cast, the result becomes smaller, [ -> (
normal_keypart_->include_start_ = false;
is_bound_modified = true;
}
if (end_cmp < 0) {
// after cast, the result becomes bigger, ] -> )
normal_keypart_->include_end_ = false;
is_bound_modified = true;
} else if (end_cmp > 0) {
// after cast, the result becomes smaller, ) -> ]
normal_keypart_->include_end_ = true;
is_bound_modified = true;
}
normal_keypart_->start_.set_collation_type(pos_.column_type_.get_collation_type());
normal_keypart_->end_.set_collation_type(pos_.column_type_.get_collation_type());
if (OB_FAIL(formalize_keypart(contain_row))) {
LOG_WARN("formalize keypart failed", K(ret));
}
}
return ret;
}
int ObKeyPart::try_cast_value(const ObDataTypeCastParams &dtc_params, ObIAllocator &alloc,
const ObKeyPartPos &pos, ObObj &value, int64_t &cmp)
{
int ret = OB_SUCCESS;
if (!value.is_min_value() && !value.is_max_value() && !value.is_unknown()
&& (!ObSQLUtils::is_same_type_for_compare(value.get_meta(), pos.column_type_.get_obj_meta())
|| value.is_decimal_int())) {
const ObObj *dest_val = NULL;
ObCollationType collation_type = pos.column_type_.get_collation_type();
ObCastCtx cast_ctx(&alloc, &dtc_params, CM_WARN_ON_FAIL, collation_type);
ObAccuracy acc(pos.column_type_.get_accuracy());
if (pos.column_type_.is_decimal_int()) {
cast_ctx.res_accuracy_ = &acc;
}
ObObj &tmp_start = value;
ObExpectType expect_type;
expect_type.set_type(pos.column_type_.get_type());
expect_type.set_collation_type(collation_type);
expect_type.set_type_infos(&pos.get_enum_set_values());
EXPR_CAST_OBJ_V2(expect_type, tmp_start, dest_val);
// to check if EXPR CAST losses number precise
ObObjType cmp_type = ObMaxType;
if (OB_FAIL(ret)) {
SQL_REWRITE_LOG(WARN, "cast obj to dest type failed", K(ret), K(value), K_(pos.column_type));
} else if (OB_FAIL(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type,
value.get_type(),
dest_val->get_type()))) {
LOG_WARN("get compare type failed", K(ret));
} else if (OB_FAIL(ObRelationalExprOperator::compare_nullsafe(cmp,
value,
*dest_val,
cast_ctx,
cmp_type,
collation_type))) {
SQL_REWRITE_LOG(WARN, "compare obj value failed", K(ret));
} else {
value = *dest_val;
}
}
return ret;
}
int ObKeyPart::create_normal_key()
{
int ret = OB_SUCCESS;
void *ptr = NULL;
if (OB_ISNULL(ptr = allocator_.alloc(sizeof(ObNormalKeyPart)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("alloc memory failed");
} else {
key_type_ = T_NORMAL_KEY;
normal_keypart_ = new(ptr) ObNormalKeyPart();
}
return ret;
}
int ObKeyPart::create_like_key()
{
int ret = OB_SUCCESS;
void *ptr = NULL;
if (OB_ISNULL(ptr = allocator_.alloc(sizeof(ObLikeKeyPart)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("alloc memory failed");
} else {
key_type_ = T_LIKE_KEY;
like_keypart_ = new(ptr) ObLikeKeyPart();
}
return ret;
}
int ObKeyPart::create_in_key()
{
int ret = OB_SUCCESS;
void *ptr = NULL;
if (OB_ISNULL(ptr = allocator_.alloc(sizeof(ObInKeyPart)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("alloc memory failed", K(ret));
} else {
key_type_ = T_IN_KEY;
in_keypart_ = new(ptr) ObInKeyPart();
in_keypart_->in_type_ = T_IN_KEY_PART;
}
return ret;
}
// to be implemented
int ObKeyPart::create_not_in_key()
{
int ret = OB_SUCCESS;
void *ptr = NULL;
if (OB_ISNULL(ptr = allocator_.alloc(sizeof(ObInKeyPart)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("alloc memory failed", K(ret));
} else {
key_type_ = T_IN_KEY;
in_keypart_ = new(ptr) ObInKeyPart();
in_keypart_->in_type_ = T_NOT_IN_KEY_PART;
}
return ret;
}
int ObKeyPart::create_geo_key()
{
int ret = OB_SUCCESS;
void *ptr = NULL;
if (OB_UNLIKELY(NULL == (ptr = allocator_.alloc(sizeof(ObGeoKeyPart))))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("alloc memory failed");
} else {
key_type_ = T_GEO_KEY;
geo_keypart_ = new(ptr) ObGeoKeyPart();
}
return ret;
}
int ObKeyPart::convert_to_true_or_false(bool is_always_true)
{
int ret = OB_SUCCESS;
if (is_in_key()) {
// set the first key part
ObKeyPartPos pos = in_keypart_->in_params_.at(0)->pos_;
if (OB_FAIL(create_normal_key())) {
LOG_WARN("failed to create normal key", K(ret));
} else {
pos_ = pos;
id_.table_id_ = in_keypart_->table_id_;
}
}
if (OB_SUCC(ret)) {
if (is_always_true) {
normal_keypart_->start_.set_min_value();
normal_keypart_->end_.set_max_value();
} else {
normal_keypart_->start_.set_max_value();
normal_keypart_->end_.set_min_value();
}
normal_keypart_->include_start_ = false;
normal_keypart_->include_end_ = false;
normal_keypart_->always_true_ = is_always_true;
normal_keypart_->always_false_ = !is_always_true;
}
return ret;
}
DEF_TO_STRING(ObKeyPart)
{
int64_t pos = 0;
J_OBJ_START();
if (!is_in_key()) {
J_KV(N_INDEX_ID, id_,
N_POS, pos_,
K_(key_type),
K_(null_safe),
K_(rowid_column_idx),
K_(is_phy_rowid_key_part));
} else {
J_KV(K_(key_type));
}
if (is_normal_key()) {
J_COMMA();
J_KV(N_START_VAL, normal_keypart_->start_,
N_END_VAL, normal_keypart_->end_,
N_INCLUDE_START, normal_keypart_->include_start_,
N_INCLUDE_END, normal_keypart_->include_end_,
N_ALWAYS_TRUE, normal_keypart_->always_true_,
N_ALWAYS_FALSE, normal_keypart_->always_false_);
} else if (is_like_key()) {
J_COMMA();
J_KV(N_PATTERN_VAL, like_keypart_->pattern_,
N_ESCAPE_VAL, like_keypart_->escape_);
} else if (is_in_key()) {
J_COMMA();
J_KV("table_id_", in_keypart_->table_id_,
N_IS_STRICT_IN, in_keypart_->is_strict_in_,
N_CONTAIN_QUESTIONMARK, in_keypart_->contain_questionmark_,
N_OFFSETS, in_keypart_->offsets_,
N_MISSING_OFFSETS, in_keypart_->missing_offsets_,
N_IN_PARAMS, in_keypart_->in_params_);
} else if (is_geo_key()) {
J_COMMA();
J_KV("wkb_", geo_keypart_->wkb_,
"geo_type_", geo_keypart_->geo_type_,
"distance_", geo_keypart_->distance_);
}
J_OBJ_END();
return pos;
}
} // namespace sql
} // namespace oceanbase