1526 lines
47 KiB
C++
1526 lines
47 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.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <algorithm>
|
|
#include <math.h> // for fabs, fabsf
|
|
#define USING_LOG_PREFIX COMMON
|
|
#include "common/object/ob_object.h"
|
|
#include "lib/utility/serialization.h"
|
|
#include "lib/utility/utility.h"
|
|
#include "lib/checksum/ob_crc64.h"
|
|
#include "common/object/ob_obj_compare.h"
|
|
#include "common/ob_action_flag.h"
|
|
#include "lib/hash_func/murmur_hash.h"
|
|
#include "lib/utility/ob_print_utils.h"
|
|
#include "lib/timezone/ob_time_convert.h"
|
|
#include "lib/number/ob_number_v2.h"
|
|
#include "lib/utility/ob_hang_fatal_error.h"
|
|
#include "lib/string/ob_sql_string.h"
|
|
#include "lib/worker.h"
|
|
#include "common/object/ob_obj_funcs.h"
|
|
|
|
using namespace oceanbase;
|
|
using namespace oceanbase::common;
|
|
|
|
int64_t ObLogicMacroBlockId::hash() const
|
|
{
|
|
int64_t hash_val = 0;
|
|
hash_val = common::murmurhash(&data_seq_, sizeof(data_seq_), hash_val);
|
|
hash_val = common::murmurhash(&data_version_, sizeof(data_version_), hash_val);
|
|
return hash_val;
|
|
}
|
|
|
|
bool ObLogicMacroBlockId::operator==(const ObLogicMacroBlockId& other) const
|
|
{
|
|
return data_seq_ == other.data_seq_ && data_version_ == other.data_version_;
|
|
}
|
|
|
|
bool ObLogicMacroBlockId::operator!=(const ObLogicMacroBlockId& other) const
|
|
{
|
|
return !(operator==(other));
|
|
}
|
|
|
|
OB_SERIALIZE_MEMBER(ObLogicMacroBlockId, data_seq_, data_version_);
|
|
|
|
bool ObLobIndex::operator==(const ObLobIndex& other) const
|
|
{
|
|
return version_ == other.version_ && logic_macro_id_ == other.logic_macro_id_ && byte_size_ == other.byte_size_ &&
|
|
char_size_ == other.char_size_;
|
|
}
|
|
|
|
bool ObLobIndex::operator!=(const ObLobIndex& other) const
|
|
{
|
|
return !(operator==(other));
|
|
}
|
|
|
|
OB_SERIALIZE_MEMBER(ObLobIndex, version_, logic_macro_id_, byte_size_, char_size_);
|
|
|
|
void ObLobData::reset()
|
|
{
|
|
version_ = LOB_DATA_VERSION;
|
|
byte_size_ = 0;
|
|
char_size_ = 0;
|
|
idx_cnt_ = 0;
|
|
}
|
|
|
|
bool ObLobData::operator==(const ObLobData& other) const
|
|
{
|
|
bool bret = version_ == other.version_ && byte_size_ == other.byte_size_ && char_size_ == other.char_size_ &&
|
|
idx_cnt_ == other.idx_cnt_;
|
|
for (int64_t i = 0; i < idx_cnt_ && bret; ++i) {
|
|
bret = lob_idx_[i] == other.lob_idx_[i];
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
bool ObLobData::operator!=(const ObLobData& other) const
|
|
{
|
|
return !(operator==(other));
|
|
}
|
|
|
|
int64_t ObLobData::get_serialize_size() const
|
|
{
|
|
int64_t serialize_size = 0;
|
|
serialize_size += serialization::encoded_length_i32(version_);
|
|
serialize_size += serialization::encoded_length_i32(idx_cnt_);
|
|
serialize_size += serialization::encoded_length_i64(byte_size_);
|
|
serialize_size += serialization::encoded_length_i64(char_size_);
|
|
for (int64_t i = 0; i < idx_cnt_; ++i) {
|
|
serialize_size += lob_idx_[i].get_serialize_size();
|
|
}
|
|
return serialize_size;
|
|
}
|
|
|
|
int ObLobData::serialize(char* buf, const int64_t buf_len, int64_t& pos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const int64_t request_size = get_serialize_size();
|
|
if (OB_UNLIKELY(NULL == buf || buf_len <= 0 || pos < 0 || pos + request_size > buf_len)) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
COMMON_LOG(WARN, "invalid arguments", K(ret), KP(buf), K(pos), K(request_size), K(buf_len));
|
|
} else if (OB_FAIL(serialization::encode_i32(buf, buf_len, pos, version_))) {
|
|
COMMON_LOG(WARN, "fail to encode version", K(ret), K(buf_len), K(pos));
|
|
} else if (OB_FAIL(serialization::encode_i32(buf, buf_len, pos, idx_cnt_))) {
|
|
COMMON_LOG(WARN, "fail to encode idx_cnt", K(ret));
|
|
} else if (OB_FAIL(serialization::encode_i64(buf, buf_len, pos, byte_size_))) {
|
|
COMMON_LOG(WARN, "fail to encode byte_size", K(ret), K(buf_len), K(pos));
|
|
} else if (OB_FAIL(serialization::encode_i64(buf, buf_len, pos, char_size_))) {
|
|
COMMON_LOG(WARN, "fail to encode char_size", K(ret), K(buf_len), K(pos));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < idx_cnt_; ++i) {
|
|
if (OB_FAIL(lob_idx_[i].serialize(buf, buf_len, pos))) {
|
|
COMMON_LOG(WARN, "fail to serialize lob index", K(ret), K(buf_len), K(pos));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLobData::deserialize(const char* buf, const int64_t buf_len, int64_t& pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(NULL == buf || buf_len <= 0 || pos > buf_len)) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
COMMON_LOG(WARN, "invalid arguments", K(ret), KP(buf), K(buf_len), K(pos));
|
|
} else if (OB_FAIL(serialization::decode_i32(buf, buf_len, pos, reinterpret_cast<int32_t*>(&version_)))) {
|
|
COMMON_LOG(WARN, "fail to decode version", K(ret));
|
|
} else if (OB_FAIL(serialization::decode_i32(buf, buf_len, pos, reinterpret_cast<int32_t*>(&idx_cnt_)))) {
|
|
COMMON_LOG(WARN, "fail to decode idx_cnt", K(ret));
|
|
} else if (OB_FAIL(serialization::decode_i64(buf, buf_len, pos, reinterpret_cast<int64_t*>(&byte_size_)))) {
|
|
COMMON_LOG(WARN, "fail to decode byte_size", K(ret));
|
|
} else if (OB_FAIL(serialization::decode_i64(buf, buf_len, pos, reinterpret_cast<int64_t*>(&char_size_)))) {
|
|
COMMON_LOG(WARN, "fail to decode char_size", K(ret));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < idx_cnt_; ++i) {
|
|
if (OB_FAIL(lob_idx_[i].deserialize(buf, buf_len, pos))) {
|
|
COMMON_LOG(WARN, "fail to deseriaze lob index", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLobLocator::init(const uint64_t table_id, const uint32_t column_id, const int64_t snapshot_version,
|
|
const uint16_t flags, const ObString& rowid, const ObString& payload)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_UNLIKELY(!is_valid_id(table_id) || !is_valid_id(column_id) || snapshot_version <= 0)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN,
|
|
"Invalid argument to init ObLobLocator",
|
|
K(table_id),
|
|
K(column_id),
|
|
K(snapshot_version),
|
|
K(rowid),
|
|
K(payload));
|
|
} else {
|
|
magic_code_ = MAGIC_CODE;
|
|
version_ = LOB_LOCATOR_VERSION;
|
|
snapshot_version_ = snapshot_version;
|
|
table_id_ = table_id;
|
|
column_id_ = column_id;
|
|
option_ = 0;
|
|
flags_ = flags;
|
|
if (rowid.empty()) {
|
|
// for old heap table withou rowid
|
|
set_compat_mode();
|
|
payload_offset_ = 0;
|
|
} else {
|
|
set_inline_mode();
|
|
payload_offset_ = rowid.length();
|
|
MEMCPY(data_, rowid.ptr(), rowid.length());
|
|
}
|
|
if (OB_NOT_NULL(payload.ptr())) {
|
|
MEMCPY(data_ + payload_offset_, payload.ptr(), payload.length());
|
|
payload_size_ = payload.length();
|
|
} else {
|
|
payload_size_ = 0;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLobLocator::init(const ObString& payload)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
magic_code_ = MAGIC_CODE;
|
|
version_ = LOB_LOCATOR_VERSION;
|
|
snapshot_version_ = 0;
|
|
table_id_ = 0;
|
|
column_id_ = 0;
|
|
option_ = 0;
|
|
flags_ = LOB_DEFAULT_FLAGS;
|
|
set_compat_mode();
|
|
payload_offset_ = 0;
|
|
if (OB_NOT_NULL(payload.ptr())) {
|
|
MEMCPY(data_ + payload_offset_, payload.ptr(), payload.length());
|
|
payload_size_ = payload.length();
|
|
} else {
|
|
payload_size_ = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLobLocator::get_rowid(ObString& rowid) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(!is_valid())) {
|
|
ret = OB_NOT_INIT;
|
|
COMMON_LOG(WARN, "ObLobLocator is not init", K(ret), K(*this));
|
|
} else if (!is_inline_mode()) {
|
|
ret = OB_NOT_SUPPORTED;
|
|
COMMON_LOG(WARN, "ObLobLocator with compat mode does not support rowid ", K(ret), K(*this));
|
|
} else if (payload_offset_ <= 0) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
COMMON_LOG(WARN, "Unexpected payload offset to get rowid", K(ret), K(*this));
|
|
} else {
|
|
rowid = ObString(payload_offset_, data_);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObLobLocator::get_payload(ObString& payload) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(!is_valid())) {
|
|
ret = OB_NOT_INIT;
|
|
COMMON_LOG(WARN, "ObLobLocator is not init", K(ret), K(*this));
|
|
} else if (payload_size_ > 0) {
|
|
payload.assign_ptr(data_ + payload_offset_, payload_size_);
|
|
} else {
|
|
payload.reset();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
DEF_TO_STRING(ObLobLocator)
|
|
{
|
|
int64_t pos = 0;
|
|
J_OBJ_START();
|
|
J_KV(K_(magic_code),
|
|
K_(version),
|
|
K_(snapshot_version),
|
|
K_(table_id),
|
|
K_(column_id),
|
|
K_(flags),
|
|
K_(option),
|
|
K_(payload_offset),
|
|
K_(payload_size));
|
|
J_COMMA();
|
|
if (buf_len > pos && is_valid()) {
|
|
int64_t max_len = buf_len - pos;
|
|
ObString payload(MIN(payload_size_, max_len), get_payload_ptr());
|
|
J_KV("data", payload);
|
|
} else {
|
|
J_KV(K_(data));
|
|
}
|
|
J_OBJ_END();
|
|
return pos;
|
|
}
|
|
|
|
#define PRINT_META()
|
|
//#define PRINT_META() BUF_PRINTO(obj.get_meta()); J_COLON();
|
|
|
|
const char* ObObj::MIN_OBJECT_VALUE_STR = "__OB__MIN__";
|
|
const char* ObObj::MAX_OBJECT_VALUE_STR = "__OB__MAX__";
|
|
const char* ObObj::NOP_VALUE_STR = "__OB__NOP__";
|
|
|
|
OB_SERIALIZE_MEMBER(ObDataType, meta_, accuracy_, is_zero_fill_);
|
|
OB_SERIALIZE_MEMBER(ObEnumSetInnerValue, numberic_value_, string_value_);
|
|
|
|
DEFINE_SERIALIZE(ObObjMeta)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
OB_UNIS_ENCODE(type_);
|
|
OB_UNIS_ENCODE(cs_level_);
|
|
OB_UNIS_ENCODE(cs_type_);
|
|
OB_UNIS_ENCODE(scale_);
|
|
return ret;
|
|
}
|
|
|
|
DEFINE_DESERIALIZE(ObObjMeta)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
OB_UNIS_DECODE(type_);
|
|
OB_UNIS_DECODE(cs_level_);
|
|
OB_UNIS_DECODE(cs_type_);
|
|
OB_UNIS_DECODE(scale_);
|
|
return ret;
|
|
}
|
|
|
|
DEFINE_GET_SERIALIZE_SIZE(ObObjMeta)
|
|
{
|
|
int64_t len = 0;
|
|
OB_UNIS_ADD_LEN(type_);
|
|
OB_UNIS_ADD_LEN(cs_level_);
|
|
OB_UNIS_ADD_LEN(cs_type_);
|
|
OB_UNIS_ADD_LEN(scale_);
|
|
return len;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
bool ObObj::is_zero() const
|
|
{
|
|
bool ret = is_numeric_type();
|
|
if (ret) {
|
|
switch (meta_.get_type()) {
|
|
case ObTinyIntType:
|
|
// fall through
|
|
case ObSmallIntType:
|
|
// fall through
|
|
case ObMediumIntType:
|
|
// fall through
|
|
case ObInt32Type:
|
|
// fall through
|
|
case ObIntType:
|
|
ret = (0 == v_.int64_);
|
|
break;
|
|
case ObUTinyIntType:
|
|
// fall through
|
|
case ObUSmallIntType:
|
|
// fall through
|
|
case ObUMediumIntType:
|
|
// fall through
|
|
case ObUInt32Type:
|
|
// fall through
|
|
case ObUInt64Type:
|
|
ret = (0 == v_.uint64_);
|
|
break;
|
|
// Please do not bother yourself too much to take +0 and -0 into consideration
|
|
// According to the IEEE754 standard, +0 equals to -0
|
|
// https://en.wikipedia.org/wiki/Signed_zero
|
|
case ObFloatType:
|
|
ret = (0 == v_.float_);
|
|
break;
|
|
case ObDoubleType:
|
|
ret = (0 == v_.double_);
|
|
break;
|
|
case ObUFloatType:
|
|
ret = (0 == v_.float_);
|
|
break;
|
|
case ObUDoubleType:
|
|
ret = (0 == v_.double_);
|
|
break;
|
|
case ObNumberType:
|
|
// fall through
|
|
case ObUNumberType:
|
|
case ObNumberFloatType: {
|
|
ret = is_zero_number();
|
|
break;
|
|
}
|
|
case ObBitType: {
|
|
ret = (0 == v_.uint64_);
|
|
break;
|
|
}
|
|
default:
|
|
BACKTRACE(ERROR, true, "unexpected numeric type=%u", meta_.get_type());
|
|
right_to_die_or_duty_to_live();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObObj::build_not_strict_default_value()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObObjType& data_type = meta_.get_type();
|
|
switch (data_type) {
|
|
case ObTinyIntType:
|
|
set_tinyint(0);
|
|
break;
|
|
case ObSmallIntType:
|
|
set_smallint(0);
|
|
break;
|
|
case ObMediumIntType:
|
|
set_mediumint(0);
|
|
break;
|
|
case ObInt32Type:
|
|
set_int32(0);
|
|
break;
|
|
case ObIntType:
|
|
set_int(0);
|
|
break;
|
|
case ObUTinyIntType:
|
|
set_utinyint(0);
|
|
break;
|
|
case ObUSmallIntType:
|
|
set_usmallint(0);
|
|
break;
|
|
case ObUMediumIntType:
|
|
set_umediumint(0);
|
|
break;
|
|
case ObUInt32Type:
|
|
set_uint32(0);
|
|
break;
|
|
case ObUInt64Type:
|
|
set_uint64(0);
|
|
break;
|
|
case ObFloatType:
|
|
set_float(0);
|
|
break;
|
|
case ObDoubleType:
|
|
set_double(0);
|
|
break;
|
|
case ObUFloatType:
|
|
set_ufloat(0);
|
|
break;
|
|
case ObUDoubleType:
|
|
set_udouble(0);
|
|
break;
|
|
case ObNumberType: {
|
|
number::ObNumber zero;
|
|
zero.set_zero();
|
|
set_number(zero);
|
|
break;
|
|
}
|
|
case ObUNumberType: {
|
|
number::ObNumber zero;
|
|
zero.set_zero();
|
|
set_unumber(zero);
|
|
break;
|
|
}
|
|
case ObDateTimeType:
|
|
set_datetime(ObTimeConverter::ZERO_DATETIME);
|
|
break;
|
|
case ObTimestampType:
|
|
set_timestamp(ObTimeConverter::ZERO_DATETIME);
|
|
break;
|
|
case ObDateType:
|
|
set_date(ObTimeConverter::ZERO_DATE);
|
|
break;
|
|
case ObTimeType:
|
|
set_time(0);
|
|
break;
|
|
case ObYearType:
|
|
set_year(0);
|
|
break;
|
|
case ObVarcharType: {
|
|
ObString null_str;
|
|
set_varchar(null_str);
|
|
} break;
|
|
case ObCharType: {
|
|
ObString null_str;
|
|
set_char(null_str);
|
|
} break;
|
|
case ObTinyTextType:
|
|
case ObTextType:
|
|
case ObMediumTextType:
|
|
case ObLongTextType: {
|
|
ObString null_str;
|
|
set_string(data_type, null_str);
|
|
meta_.set_lob_inrow();
|
|
} break;
|
|
case ObBitType:
|
|
set_bit(0);
|
|
break;
|
|
case ObEnumType:
|
|
set_enum(1);
|
|
break;
|
|
case ObSetType:
|
|
set_set(0);
|
|
break;
|
|
case ObTimestampTZType:
|
|
case ObTimestampLTZType:
|
|
case ObTimestampNanoType: {
|
|
set_otimestamp_null(data_type);
|
|
break;
|
|
}
|
|
case ObRawType: {
|
|
ObString null_str;
|
|
set_raw(null_str);
|
|
break;
|
|
}
|
|
case ObIntervalYMType: {
|
|
const ObIntervalYMValue empty_value;
|
|
set_interval_ym(empty_value);
|
|
break;
|
|
}
|
|
case ObIntervalDSType: {
|
|
const ObIntervalDSValue empty_value;
|
|
set_interval_ds(empty_value);
|
|
break;
|
|
}
|
|
case ObNumberFloatType: {
|
|
number::ObNumber zero;
|
|
zero.set_zero();
|
|
set_number_float(zero);
|
|
break;
|
|
}
|
|
case ObURowIDType: {
|
|
ObURowIDData urowid_data;
|
|
set_urowid(urowid_data);
|
|
break;
|
|
}
|
|
default:
|
|
ret = OB_INVALID_ARGUMENT;
|
|
_OB_LOG(WARN, "unexpected data type=%u", data_type);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObObj::deep_copy(const ObObj& src, char* buf, const int64_t size, int64_t& pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (ob_is_string_type(src.get_type())) {
|
|
ObString src_str = src.get_string();
|
|
if (OB_UNLIKELY(size < (pos + src_str.length()))) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
} else {
|
|
MEMCPY(buf + pos, src_str.ptr(), src_str.length());
|
|
*this = src;
|
|
this->set_string(src.get_type(), buf + pos, src_str.length());
|
|
pos += src_str.length();
|
|
}
|
|
} else if (ob_is_raw(src.get_type())) {
|
|
const ObString& src_str = src.get_string();
|
|
if (OB_UNLIKELY(size < (pos + src_str.length()))) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
} else {
|
|
MEMCPY(buf + pos, src_str.ptr(), src_str.length());
|
|
*this = src;
|
|
this->set_raw(buf + pos, src_str.length());
|
|
pos += src_str.length();
|
|
}
|
|
} else if (ob_is_number_tc(src.get_type())) {
|
|
const int64_t number_size = src.get_number_byte_length();
|
|
if (OB_UNLIKELY(size < (int64_t)(pos + number_size))) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
} else {
|
|
MEMCPY(buf + pos, src.get_number_digits(), number_size);
|
|
*this = src;
|
|
this->set_number(src.get_type(), src.get_number_desc(), (uint32_t*)(buf + pos));
|
|
pos += number_size;
|
|
}
|
|
} else if (ob_is_rowid_tc(src.get_type())) {
|
|
if (OB_UNLIKELY(size < (int64_t)(pos + src.get_string_len()))) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
} else {
|
|
MEMCPY(buf + pos, src.get_string_ptr(), src.get_string_len());
|
|
*this = src;
|
|
this->set_urowid(buf + pos, src.get_string_len());
|
|
pos += src.get_string_len();
|
|
}
|
|
} else if (ob_is_lob_locator(src.get_type())) {
|
|
if (OB_UNLIKELY(size < (pos + src.get_val_len()))) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
} else {
|
|
// copy all the value
|
|
MEMCPY(buf + pos, src.get_string_ptr(), src.get_val_len());
|
|
*this = src;
|
|
ObLobLocator* res = reinterpret_cast<ObLobLocator*>((buf + pos));
|
|
this->set_lob_locator(*res);
|
|
pos += src.get_val_len();
|
|
}
|
|
} else {
|
|
*this = src;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObObj::can_compare(const ObObj& other) const
|
|
{
|
|
obj_cmp_func cmp_func = NULL;
|
|
return (is_min_value() || is_max_value() || other.is_min_value() || other.is_max_value() ||
|
|
ObObjCmpFuncs::can_cmp_without_cast(get_meta(), other.get_meta(), CO_CMP, cmp_func));
|
|
}
|
|
|
|
int ObObj::check_collation_free_and_compare(const ObObj& other, int& cmp) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
cmp = 0;
|
|
if (CS_TYPE_COLLATION_FREE != get_collation_type() && CS_TYPE_COLLATION_FREE != other.get_collation_type()) {
|
|
ret = compare(other, CS_TYPE_INVALID, cmp);
|
|
} else if (is_null() || other.is_null() || is_min_value() || is_max_value() || other.is_min_value() ||
|
|
other.is_max_value()) {
|
|
ret = ObObjCmpFuncs::compare(*this, other, CS_TYPE_INVALID, cmp);
|
|
} else if (OB_UNLIKELY(get_collation_type() != other.get_collation_type()) ||
|
|
CS_TYPE_COLLATION_FREE != get_collation_type() || get_type() != other.get_type() || !is_character_type()) {
|
|
LOG_ERROR("unexpected error, invalid argument", K(*this), K(other));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else {
|
|
const int32_t lhs_len = get_val_len();
|
|
const int32_t rhs_len = other.get_val_len();
|
|
const int32_t cmp_len = std::min(lhs_len, rhs_len);
|
|
const bool is_oracle = lib::is_oracle_mode();
|
|
bool need_skip_tail_space = false;
|
|
cmp = memcmp(get_string_ptr(), other.get_string_ptr(), cmp_len);
|
|
// if two strings only have different trailing spaces:
|
|
// 1. in oracle varchar mode, the strings are considered to be different,
|
|
// 2. in oracle char mode, the strings are considered to be same,
|
|
// 3. in mysql mode, the strings are considered to be different.
|
|
if (is_oracle) {
|
|
if (0 == cmp) {
|
|
if (!is_varying_len_char_type()) {
|
|
need_skip_tail_space = true;
|
|
} else if (lhs_len != cmp_len || rhs_len != cmp_len) {
|
|
cmp = lhs_len > cmp_len ? 1 : -1;
|
|
}
|
|
}
|
|
} else if (0 == cmp && (lhs_len != cmp_len || rhs_len != cmp_len)) {
|
|
need_skip_tail_space = true;
|
|
}
|
|
if (need_skip_tail_space) {
|
|
bool has_non_space = false;
|
|
const int32_t left_len = (lhs_len > cmp_len) ? lhs_len - cmp_len : rhs_len - cmp_len;
|
|
const char* ptr = (lhs_len > cmp_len) ? get_string_ptr() : other.get_string_ptr();
|
|
const unsigned char* uptr = reinterpret_cast<const unsigned char*>(ptr);
|
|
int32_t i = 0;
|
|
uptr += cmp_len;
|
|
for (; i < left_len; ++i) {
|
|
if (*(uptr + i) != ' ') {
|
|
has_non_space = true;
|
|
break;
|
|
}
|
|
}
|
|
if (has_non_space) {
|
|
// special behavior of mysql: a\1 < a, but ab > a
|
|
if (*(uptr + i) < ' ') {
|
|
cmp = lhs_len > cmp_len ? -1 : 1;
|
|
} else {
|
|
cmp = lhs_len > cmp_len ? 1 : -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// TODO : remove this function
|
|
int ObObj::check_collation_free_and_compare(const ObObj& other) const
|
|
{
|
|
int cmp = 0;
|
|
if (CS_TYPE_COLLATION_FREE != get_collation_type() && CS_TYPE_COLLATION_FREE != other.get_collation_type()) {
|
|
cmp = compare(other, CS_TYPE_INVALID);
|
|
} else if (is_null() || other.is_null() || is_min_value() || is_max_value() || other.is_min_value() ||
|
|
other.is_max_value()) {
|
|
cmp = ObObjCmpFuncs::compare_nullsafe(*this, other, CS_TYPE_INVALID);
|
|
} else if (OB_UNLIKELY(get_collation_type() != other.get_collation_type()) ||
|
|
CS_TYPE_COLLATION_FREE != get_collation_type() || get_type() != other.get_type() || !is_character_type()) {
|
|
LOG_ERROR("unexpected error, invalid argument", K(*this), K(other));
|
|
right_to_die_or_duty_to_live();
|
|
} else {
|
|
const int32_t lhs_len = get_val_len();
|
|
const int32_t rhs_len = other.get_val_len();
|
|
const int32_t cmp_len = std::min(lhs_len, rhs_len);
|
|
const bool is_oracle = lib::is_oracle_mode();
|
|
bool need_skip_tail_space = false;
|
|
cmp = memcmp(get_string_ptr(), other.get_string_ptr(), cmp_len);
|
|
// if two strings only have different trailing spaces:
|
|
// 1. in oracle varchar mode, the strings are considered to be different,
|
|
// 2. in oracle char mode, the strings are considered to be same,
|
|
// 3. in mysql mode, the strings are considered to be different.
|
|
if (is_oracle) {
|
|
if (0 == cmp) {
|
|
if (!is_varying_len_char_type()) {
|
|
need_skip_tail_space = true;
|
|
} else if (lhs_len != cmp_len || rhs_len != cmp_len) {
|
|
cmp = lhs_len > cmp_len ? 1 : -1;
|
|
}
|
|
}
|
|
} else if (0 == cmp && (lhs_len != cmp_len || rhs_len != cmp_len)) {
|
|
need_skip_tail_space = true;
|
|
}
|
|
if (need_skip_tail_space) {
|
|
bool has_non_space = false;
|
|
const int32_t left_len = (lhs_len > cmp_len) ? lhs_len - cmp_len : rhs_len - cmp_len;
|
|
const char* ptr = (lhs_len > cmp_len) ? get_string_ptr() : other.get_string_ptr();
|
|
const unsigned char* uptr = reinterpret_cast<const unsigned char*>(ptr);
|
|
int32_t i = 0;
|
|
uptr += cmp_len;
|
|
for (; i < left_len; ++i) {
|
|
if (*(uptr + i) != ' ') {
|
|
has_non_space = true;
|
|
break;
|
|
}
|
|
}
|
|
if (has_non_space) {
|
|
// special behavior of mysql: a\1 < a, but ab > a
|
|
if (*(uptr + i) < ' ') {
|
|
cmp = lhs_len > cmp_len ? -1 : 1;
|
|
} else {
|
|
cmp = lhs_len > cmp_len ? 1 : -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return cmp;
|
|
}
|
|
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
|
|
int ObObj::compare(const ObObj& other, int& cmp) const
|
|
{
|
|
return ObObjCmpFuncs::compare(*this, other, CS_TYPE_INVALID, cmp);
|
|
}
|
|
|
|
// TODO : remove this function
|
|
int ObObj::compare(const ObObj& other) const
|
|
{
|
|
return ObObjCmpFuncs::compare_nullsafe(*this, other, CS_TYPE_INVALID);
|
|
}
|
|
|
|
int ObObj::compare(const ObObj& other, ObCollationType cs_type, int& cmp) const
|
|
{
|
|
return ObObjCmpFuncs::compare(*this, other, cs_type, cmp);
|
|
}
|
|
|
|
// TODO : remove this function
|
|
int ObObj::compare(const ObObj& other, ObCollationType cs_type /*COLLATION_TYPE_MAX*/) const
|
|
{
|
|
return ObObjCmpFuncs::compare_nullsafe(*this, other, cs_type);
|
|
}
|
|
|
|
int ObObj::compare(const ObObj& other, ObCompareCtx& cmp_ctx, int& cmp) const
|
|
{
|
|
return ObObjCmpFuncs::compare(*this, other, cmp_ctx, cmp);
|
|
}
|
|
|
|
// TODO : remove this function
|
|
int ObObj::compare(const ObObj& other, ObCompareCtx& cmp_ctx) const
|
|
{
|
|
return ObObjCmpFuncs::compare_nullsafe(*this, other, cmp_ctx);
|
|
}
|
|
|
|
int ObObj::compare(const ObObj& other, ObCollationType cs_type, const ObCmpNullPos null_pos) const
|
|
{
|
|
ObCompareCtx cmp_ctx(ObMaxType, cs_type, true, INVALID_TZ_OFF, null_pos);
|
|
return ObObjCmpFuncs::compare_nullsafe(*this, other, cmp_ctx);
|
|
}
|
|
|
|
int ObObj::equal(const ObObj& other, bool& is_equal) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper(*this, other, CS_TYPE_INVALID, CO_EQ, is_equal);
|
|
}
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
bool ObObj::is_equal(const ObObj& other) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper_nullsafe(*this, other, CS_TYPE_INVALID, CO_EQ);
|
|
}
|
|
|
|
int ObObj::equal(const ObObj& other, ObCollationType cs_type, bool& is_equal) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper(*this, other, cs_type, CO_EQ, is_equal);
|
|
}
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
bool ObObj::is_equal(const ObObj& other, ObCollationType cs_type) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper_nullsafe(*this, other, cs_type, CO_EQ);
|
|
}
|
|
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
bool ObObj::operator<(const ObObj& other) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper_nullsafe(*this, other, CS_TYPE_INVALID, CO_LT);
|
|
}
|
|
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
bool ObObj::operator>(const ObObj& other) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper_nullsafe(*this, other, CS_TYPE_INVALID, CO_GT);
|
|
}
|
|
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
bool ObObj::operator>=(const ObObj& other) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper_nullsafe(*this, other, CS_TYPE_INVALID, CO_GE);
|
|
}
|
|
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
bool ObObj::operator<=(const ObObj& other) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper_nullsafe(*this, other, CS_TYPE_INVALID, CO_LE);
|
|
}
|
|
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
bool ObObj::operator==(const ObObj& other) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper_nullsafe(*this, other, CS_TYPE_INVALID, CO_EQ);
|
|
}
|
|
|
|
/*
|
|
* ATTENTION:
|
|
*
|
|
* that_obj MUST have same type with this obj (*this)
|
|
*/
|
|
bool ObObj::operator!=(const ObObj& other) const
|
|
{
|
|
return ObObjCmpFuncs::compare_oper_nullsafe(*this, other, CS_TYPE_INVALID, CO_NE);
|
|
}
|
|
|
|
int ObObj::apply(const ObObj& mutation)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int org_type = get_type();
|
|
int mut_type = mutation.get_type();
|
|
if (OB_UNLIKELY(
|
|
ObMaxType <= mut_type ||
|
|
(ObExtendType != org_type && ObNullType != org_type && ObExtendType != mut_type && ObNullType != mut_type &&
|
|
org_type != mut_type && !(ObLongTextType == org_type && ObLobType == mut_type)))) {
|
|
_OB_LOG(WARN, "type not coincident or invalid type[this->type:%d,mutation.type:%d]", org_type, mut_type);
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
switch (mut_type) {
|
|
case ObNullType:
|
|
set_null();
|
|
break;
|
|
case ObExtendType: {
|
|
int64_t org_ext = get_ext();
|
|
switch (mutation.get_ext()) {
|
|
case ObActionFlag::OP_DEL_ROW:
|
|
case ObActionFlag::OP_DEL_TABLE:
|
|
/// used for join, if right row was deleted, set the cell to null
|
|
set_null();
|
|
break;
|
|
case ObActionFlag::OP_ROW_DOES_NOT_EXIST:
|
|
/// do nothing
|
|
break;
|
|
case ObActionFlag::OP_NOP:
|
|
if (org_ext == ObActionFlag::OP_ROW_DOES_NOT_EXIST || org_ext == ObActionFlag::OP_DEL_ROW) {
|
|
set_null();
|
|
}
|
|
break;
|
|
default:
|
|
ret = OB_INVALID_ARGUMENT;
|
|
_OB_LOG(ERROR, "unsupported ext value [value:%ld]", mutation.get_ext());
|
|
break;
|
|
} // end switch
|
|
break;
|
|
}
|
|
default:
|
|
*this = mutation;
|
|
break;
|
|
} // end switch
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
#define DEF_FUNC_ENTRY(OBJTYPE) \
|
|
{ \
|
|
obj_print_sql<OBJTYPE>, obj_print_str<OBJTYPE>, obj_print_plain_str<OBJTYPE>, obj_print_json<OBJTYPE>, \
|
|
obj_crc64<OBJTYPE>, obj_crc64_v2<OBJTYPE>, obj_batch_checksum<OBJTYPE>, obj_murmurhash<OBJTYPE>, \
|
|
ObjHashCalculator<OBJTYPE, ObDefaultHash, ObObj>::calc_hash_value, obj_val_serialize<OBJTYPE>, \
|
|
obj_val_deserialize<OBJTYPE>, obj_val_get_serialize_size<OBJTYPE>, \
|
|
ObjHashCalculator<OBJTYPE, ObWyHash, ObObj>::calc_hash_value, obj_crc64_v3<OBJTYPE>, \
|
|
ObjHashCalculator<OBJTYPE, ObXxHash, ObObj>::calc_hash_value, \
|
|
ObjHashCalculator<OBJTYPE, ObMurmurHash, ObObj>::calc_hash_value, \
|
|
}
|
|
|
|
ObObjTypeFuncs OBJ_FUNCS[ObMaxType] = {
|
|
DEF_FUNC_ENTRY(ObNullType), // 0
|
|
DEF_FUNC_ENTRY(ObTinyIntType), // 1
|
|
DEF_FUNC_ENTRY(ObSmallIntType), // 2
|
|
DEF_FUNC_ENTRY(ObMediumIntType), // 3
|
|
DEF_FUNC_ENTRY(ObInt32Type), // 4
|
|
DEF_FUNC_ENTRY(ObIntType), // 5
|
|
DEF_FUNC_ENTRY(ObUTinyIntType), // 6
|
|
DEF_FUNC_ENTRY(ObUSmallIntType), // 7
|
|
DEF_FUNC_ENTRY(ObUMediumIntType), // 8
|
|
DEF_FUNC_ENTRY(ObUInt32Type), // 9
|
|
DEF_FUNC_ENTRY(ObUInt64Type), // 10
|
|
DEF_FUNC_ENTRY(ObFloatType), // 11
|
|
DEF_FUNC_ENTRY(ObDoubleType), // 12
|
|
DEF_FUNC_ENTRY(ObUFloatType), // 13
|
|
DEF_FUNC_ENTRY(ObUDoubleType), // 14
|
|
DEF_FUNC_ENTRY(ObNumberType), // 15
|
|
DEF_FUNC_ENTRY(ObUNumberType), // 16: unumber is the same as number
|
|
DEF_FUNC_ENTRY(ObDateTimeType), // 17
|
|
DEF_FUNC_ENTRY(ObTimestampType), // 18
|
|
DEF_FUNC_ENTRY(ObDateType), // 19
|
|
DEF_FUNC_ENTRY(ObTimeType), // 20
|
|
DEF_FUNC_ENTRY(ObYearType), // 21
|
|
DEF_FUNC_ENTRY(ObVarcharType), // 22, varchar
|
|
DEF_FUNC_ENTRY(ObCharType), // 23, char
|
|
DEF_FUNC_ENTRY(ObHexStringType), // 24, hex_string
|
|
DEF_FUNC_ENTRY(ObExtendType), // 25, ext
|
|
DEF_FUNC_ENTRY(ObUnknownType), // 26, unknown
|
|
DEF_FUNC_ENTRY(ObTinyTextType), // 27, tiny_text
|
|
DEF_FUNC_ENTRY(ObTextType), // 28, text
|
|
DEF_FUNC_ENTRY(ObMediumTextType), // 29, medium_text
|
|
DEF_FUNC_ENTRY(ObLongTextType), // 30, longtext
|
|
DEF_FUNC_ENTRY(ObBitType), // 31, bit
|
|
DEF_FUNC_ENTRY(ObEnumType), // 32, enum
|
|
DEF_FUNC_ENTRY(ObSetType), // 33, set
|
|
DEF_FUNC_ENTRY(ObEnumInnerType), // 34, enum
|
|
DEF_FUNC_ENTRY(ObSetInnerType), // 35, set
|
|
DEF_FUNC_ENTRY(ObTimestampTZType), // 36, timestamp with time zone
|
|
DEF_FUNC_ENTRY(ObTimestampLTZType), // 37, timestamp with local time zone
|
|
DEF_FUNC_ENTRY(ObTimestampNanoType), // 38, timestamp (9)
|
|
DEF_FUNC_ENTRY(ObRawType), // 39, timestamp (9)
|
|
DEF_FUNC_ENTRY(ObIntervalYMType), // 40, interval year to month
|
|
DEF_FUNC_ENTRY(ObIntervalDSType), // 41, interval day to second
|
|
DEF_FUNC_ENTRY(ObNumberFloatType), // 42, number float
|
|
DEF_FUNC_ENTRY(ObNVarchar2Type), // 43, nvarchar2
|
|
DEF_FUNC_ENTRY(ObNCharType), // 44, nchar
|
|
DEF_FUNC_ENTRY(ObURowIDType), // 45, urowid
|
|
DEF_FUNC_ENTRY(ObLobType), // 46, lob
|
|
};
|
|
|
|
ob_obj_hash ObObjUtil::get_murmurhash_v3(ObObjType type)
|
|
{
|
|
return OBJ_FUNCS[type].murmurhash_v3;
|
|
}
|
|
|
|
ob_obj_hash ObObjUtil::get_murmurhash_v2(ObObjType type)
|
|
{
|
|
return OBJ_FUNCS[type].murmurhash_v2;
|
|
}
|
|
|
|
ob_obj_hash ObObjUtil::get_wyhash(ObObjType type)
|
|
{
|
|
return OBJ_FUNCS[type].wyhash;
|
|
}
|
|
|
|
ob_obj_crc64_v3 ObObjUtil::get_crc64_v3(ObObjType type)
|
|
{
|
|
return ::OBJ_FUNCS[type].crc64_v3;
|
|
}
|
|
|
|
ob_obj_hash ObObjUtil::get_xxhash64(ObObjType type)
|
|
{
|
|
return ::OBJ_FUNCS[type].xxhash64;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
int ObObj::print_sql_literal(char* buffer, int64_t length, int64_t& pos, const ObObjPrintParams& params) const
|
|
{
|
|
return OBJ_FUNCS[meta_.get_type()].print_sql(*this, buffer, length, pos, params);
|
|
}
|
|
|
|
// used for show create table default value
|
|
// for example:
|
|
// `a` int(11) NOT NULL DEFAULT '0' (with '')
|
|
// always with ''
|
|
int ObObj::print_varchar_literal(char* buffer, int64_t length, int64_t& pos, const ObObjPrintParams& params) const
|
|
{
|
|
return OBJ_FUNCS[meta_.get_type()].print_str(*this, buffer, length, pos, params);
|
|
}
|
|
|
|
int ObObj::print_plain_str_literal(char* buffer, int64_t length, int64_t& pos, const ObObjPrintParams& params) const
|
|
{
|
|
return OBJ_FUNCS[meta_.get_type()].print_plain_str(*this, buffer, length, pos, params);
|
|
}
|
|
|
|
void ObObj::print_str_with_repeat(char* buf, int64_t buf_len, int64_t& pos) const
|
|
{
|
|
const unsigned char* uptr = reinterpret_cast<const unsigned char*>(v_.string_);
|
|
int32_t real_len = val_len_;
|
|
int32_t repeats = 0;
|
|
int8_t cnt_space = 0; // There is no space for whole multibyte character, then add trailing spaces.
|
|
if (NULL != uptr && real_len > 0) {
|
|
while (' ' == uptr[real_len - 1]) {
|
|
--real_len;
|
|
++cnt_space;
|
|
}
|
|
// for utf-8 character set, pad BFBFEF as the tailing characters in a loop
|
|
while (real_len - 2 > 0 && 0xBF == uptr[real_len - 1] && 0xBF == uptr[real_len - 2] && 0xEF == uptr[real_len - 3]) {
|
|
real_len -= 3;
|
|
++repeats;
|
|
}
|
|
}
|
|
if (0 == repeats) {
|
|
real_len = val_len_;
|
|
}
|
|
BUF_PRINTO(ObString(0, real_len, v_.string_));
|
|
if (repeats > 0) {
|
|
BUF_PRINTF(" \'<%X%X%X><repeat %d times>\' ", uptr[real_len], uptr[real_len + 1], uptr[real_len + 2], repeats);
|
|
// There is no space for whole multibyte character, then add trailing spaces.
|
|
if (1 == cnt_space) {
|
|
BUF_PRINTO(" ");
|
|
} else if (2 == cnt_space) {
|
|
BUF_PRINTO(" ");
|
|
}
|
|
}
|
|
}
|
|
|
|
int ObObj::print_smart(char* buf, int64_t buf_len, int64_t& pos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (get_type() < ObMaxType && get_type() >= ObNullType) {
|
|
ObObjPrintParams params;
|
|
bool can_print = true;
|
|
if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len <= 0)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else if (!(meta_.is_string_or_lob_locator_type() && ObHexStringType != meta_.get_type())) {
|
|
ret = OBJ_FUNCS[meta_.get_type()].print_json(*this, buf, buf_len, pos, params);
|
|
} else if (OB_FAIL(is_printable(get_string_ptr(), get_string_len(), can_print))) {
|
|
} else if (can_print) {
|
|
ret = OBJ_FUNCS[meta_.get_type()].print_json(*this, buf, buf_len, pos, params);
|
|
} else {
|
|
J_OBJ_START();
|
|
PRINT_META();
|
|
BUF_PRINTO(ob_obj_type_str(get_type()));
|
|
J_COLON();
|
|
if (OB_FAIL(obj_print_sql<ObHexStringType>(*this, buf, buf_len, pos, params))) {
|
|
} else {
|
|
J_COMMA();
|
|
J_KV(N_COLLATION, ObCharset::collation_name(get_collation_type()));
|
|
J_OBJ_END();
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObObj::print_format(char* buf, int64_t buf_len, int64_t& pos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (get_type() < ObMaxType && get_type() >= ObNullType) {
|
|
ObObjPrintParams params;
|
|
bool can_print = true;
|
|
if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len <= 0)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else if (!(meta_.is_string_type() && ObHexStringType != meta_.get_type())) {
|
|
ret = OBJ_FUNCS[meta_.get_type()].print_sql(*this, buf, buf_len, pos, params);
|
|
} else if (OB_FAIL(is_printable(get_string_ptr(), get_string_len(), can_print))) {
|
|
} else if (can_print) {
|
|
ret = OBJ_FUNCS[meta_.get_type()].print_sql(*this, buf, buf_len, pos, params);
|
|
} else {
|
|
ret = obj_print_sql<ObHexStringType>(*this, buf, buf_len, pos, params);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObObj::print_range_value(char* buf, int64_t buf_len, int64_t& pos) const
|
|
{
|
|
if (is_string_type()) {
|
|
J_OBJ_START();
|
|
BUF_PRINTO(ob_obj_type_str(this->get_type()));
|
|
J_COLON();
|
|
// for Unicode character set
|
|
print_str_with_repeat(buf, buf_len, pos);
|
|
J_COMMA();
|
|
J_KV(N_COLLATION, ObCharset::collation_name(this->get_collation_type()));
|
|
J_OBJ_END();
|
|
} else {
|
|
(void)databuff_print_obj(buf, buf_len, pos, *this);
|
|
}
|
|
}
|
|
|
|
int64_t ObObj::to_string(char* buf, const int64_t buf_len, const ObObjPrintParams& params) const
|
|
{
|
|
int64_t pos = 0;
|
|
if (get_type() < ObMaxType && get_type() >= ObNullType) {
|
|
(void)OBJ_FUNCS[meta_.get_type()].print_json(*this, buf, buf_len, pos, params);
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
bool ObObj::check_collation_integrity() const
|
|
{
|
|
bool is_ok = true;
|
|
#ifndef NDEBUG
|
|
if (ObNullType == get_type()) {
|
|
// ignore null
|
|
// is_ok = (CS_TYPE_BINARY == get_collation_type() && CS_LEVEL_IGNORABLE == get_collation_level());
|
|
} else if (ob_is_numeric_type(get_type()) || ob_is_temporal_type(get_type())) {
|
|
is_ok = (CS_TYPE_BINARY == get_collation_type() && CS_LEVEL_NUMERIC == get_collation_level());
|
|
} else {
|
|
// ignore: varchar, char, binary, varbinary, unknown, ext
|
|
}
|
|
if (!is_ok) {
|
|
if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) {
|
|
BACKTRACE(WARN, true, "unexpected collation type: %s", to_cstring(get_meta()));
|
|
}
|
|
}
|
|
#endif
|
|
return is_ok;
|
|
}
|
|
|
|
uint64_t ObObj::hash_v1(uint64_t seed) const
|
|
{
|
|
check_collation_integrity();
|
|
return OBJ_FUNCS[meta_.get_type()].murmurhash(*this, seed);
|
|
}
|
|
|
|
uint64_t ObObj::hash(uint64_t seed) const
|
|
{
|
|
check_collation_integrity();
|
|
return OBJ_FUNCS[meta_.get_type()].murmurhash_v2(*this, seed);
|
|
}
|
|
|
|
uint64_t ObObj::hash_murmur(uint64_t seed) const
|
|
{
|
|
check_collation_integrity();
|
|
return OBJ_FUNCS[meta_.get_type()].murmurhash_v3(*this, seed);
|
|
}
|
|
|
|
uint64_t ObObj::hash_wy(uint64_t seed) const
|
|
{
|
|
check_collation_integrity();
|
|
return OBJ_FUNCS[meta_.get_type()].wyhash(*this, seed);
|
|
}
|
|
|
|
uint64_t ObObj::hash_xx(uint64_t seed) const
|
|
{
|
|
check_collation_integrity();
|
|
return OBJ_FUNCS[meta_.get_type()].xxhash64(*this, seed);
|
|
}
|
|
|
|
int64_t ObObj::checksum(const int64_t current) const
|
|
{
|
|
check_collation_integrity();
|
|
return OBJ_FUNCS[meta_.get_type()].crc64(*this, current);
|
|
}
|
|
|
|
int64_t ObObj::checksum_v2(const int64_t current) const
|
|
{
|
|
check_collation_integrity();
|
|
return OBJ_FUNCS[meta_.get_type()].crc64_v2(*this, current);
|
|
}
|
|
|
|
void ObObj::checksum(ObBatchChecksum& bc) const
|
|
{
|
|
check_collation_integrity();
|
|
OBJ_FUNCS[meta_.get_type()].batch_checksum(*this, bc);
|
|
}
|
|
|
|
void ObObj::dump(const int32_t log_level /*= OB_LOG_LEVEL_DEBUG*/) const
|
|
{
|
|
_OB_NUM_LEVEL_LOG(log_level, "%s", S(*this));
|
|
}
|
|
|
|
int ObObj::print_varchar_literal(const ObIArray<ObString>& type_infos, char* buffer, int64_t length, int64_t& pos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSqlString str_val;
|
|
if (OB_UNLIKELY(!meta_.is_enum_or_set())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected obj type", KPC(this), K(ret));
|
|
} else if (is_enum()) {
|
|
if (OB_FAIL(get_enum_str_val(str_val, type_infos))) {
|
|
LOG_WARN("fail to get enum str val", K(str_val), K(type_infos), K(ret));
|
|
}
|
|
} else {
|
|
if (OB_FAIL(get_set_str_val(str_val, type_infos))) {
|
|
LOG_WARN("fail to get set str val", K(str_val), K(type_infos), K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) &&
|
|
databuff_printf(buffer, length, pos, "'%.*s'", static_cast<int32_t>(str_val.length()), str_val.ptr())) {
|
|
LOG_WARN("fail to print string", K(buffer), K(length), K(pos), K(str_val), K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObObj::print_plain_str_literal(
|
|
const ObIArray<ObString>& type_infos, char* buffer, int64_t length, int64_t& pos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSqlString str_val;
|
|
if (OB_UNLIKELY(!meta_.is_enum_or_set())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected obj type", KPC(this), K(ret));
|
|
} else if (is_enum()) {
|
|
if (OB_FAIL(get_enum_str_val(str_val, type_infos))) {
|
|
LOG_WARN("fail to get enum str val", K(str_val), K(type_infos), K(ret));
|
|
}
|
|
} else {
|
|
if (OB_FAIL(get_set_str_val(str_val, type_infos))) {
|
|
LOG_WARN("fail to get set str val", K(str_val), K(type_infos), K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) &&
|
|
databuff_printf(buffer, length, pos, "%.*s", static_cast<int32_t>(str_val.length()), str_val.ptr())) {
|
|
LOG_WARN("fail to print string", K(buffer), K(length), K(pos), K(str_val), K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObObj::get_enum_str_val(ObSqlString& str_val, const ObIArray<ObString>& type_infos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(!meta_.is_enum())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected type", KPC(this), K(ret));
|
|
} else {
|
|
uint64_t val = get_enum();
|
|
if (OB_UNLIKELY(val > type_infos.count())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected obj value", K(type_infos), KPC(this), K(ret));
|
|
} else if (0 == val) {
|
|
if (OB_FAIL(str_val.append(ObString("")))) {
|
|
LOG_WARN("fail to append string", K(str_val), K(ret));
|
|
}
|
|
} else {
|
|
const ObString& type_info = type_infos.at(val - 1); // enum value start from 1
|
|
if (OB_FAIL(str_val.append(type_info))) {
|
|
LOG_WARN("fail to append string", K(str_val), K(type_info), K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObObj::get_set_str_val(ObSqlString& str_val, const ObIArray<ObString>& type_infos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(!meta_.is_set())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected type", KPC(this), K(ret));
|
|
} else {
|
|
uint64_t val = get_set();
|
|
int64_t type_info_cnt = type_infos.count();
|
|
if (OB_UNLIKELY(type_info_cnt > 64 || type_info_cnt <= 0)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected type infos", K(type_infos), K(ret));
|
|
} else if (OB_UNLIKELY(type_info_cnt < 64 && (val > ((1ULL << type_info_cnt) - 1)))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected obj value", K(val), K(type_infos), K(ret));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < type_info_cnt; ++i) {
|
|
if (val & (1ULL << i)) {
|
|
if (OB_FAIL(str_val.append(type_infos.at(i)))) {
|
|
LOG_WARN("fail to append string", K(str_val), K(type_infos.at(i)), K(ret));
|
|
} else if (OB_FAIL(str_val.append(","))) {
|
|
LOG_WARN("fail to print string", K(str_val), K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (val != 0 && OB_FAIL(str_val.set_length(str_val.length() - 1))) { // remove last comma
|
|
LOG_WARN("fail to str length", K(str_val), K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObObj::get_char_length(const ObAccuracy accuracy, int32_t& char_len, bool is_oracle_mode) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (!is_fixed_len_char_type()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("type must be char", K(get_type()));
|
|
} else {
|
|
if (is_oracle_byte_length(is_oracle_mode, accuracy.get_length_semantics())) {
|
|
// get byte length
|
|
char_len = static_cast<int32_t>(get_val_len());
|
|
} else {
|
|
// get char length
|
|
char_len = static_cast<int32_t>(ObCharset::strlen_char(get_collation_type(), get_string_ptr(), get_val_len()));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObObj::convert_string_value_charset(ObCharsetType charset_type, ObIAllocator& allocator)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObString str;
|
|
get_string(str);
|
|
if (ObCharset::is_valid_charset(charset_type) && CHARSET_BINARY != charset_type) {
|
|
ObCollationType collation_type = ObCharset::get_default_collation(charset_type);
|
|
const ObCharsetInfo* from_charset_info = ObCharset::get_charset(get_collation_type());
|
|
const ObCharsetInfo* to_charset_info = ObCharset::get_charset(collation_type);
|
|
if (OB_ISNULL(from_charset_info) || OB_ISNULL(to_charset_info)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("charsetinfo is null", K(ret), K(get_collation_type()), K(collation_type));
|
|
} else if (CS_TYPE_INVALID == get_collation_type() || CS_TYPE_INVALID == collation_type) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid collation", K(get_collation_type()), K(collation_type), K(ret));
|
|
} else if (CS_TYPE_BINARY != get_collation_type() && CS_TYPE_BINARY != collation_type &&
|
|
strcmp(from_charset_info->csname, to_charset_info->csname) != 0) {
|
|
char* buf = NULL;
|
|
int32_t buf_len = str.length() * 4;
|
|
uint32_t result_len = 0;
|
|
if (0 == buf_len) {
|
|
// do noting
|
|
} else if (OB_UNLIKELY(NULL == (buf = static_cast<char*>(allocator.alloc(buf_len))))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("alloc memory failed", K(ret), K(buf_len));
|
|
} else {
|
|
ret = ObCharset::charset_convert(
|
|
get_collation_type(), str.ptr(), str.length(), collation_type, buf, buf_len, result_len);
|
|
if (OB_SUCCESS != ret) {
|
|
int32_t str_offset = 0;
|
|
int64_t buf_offset = 0;
|
|
ObString question_mark = ObCharsetUtils::get_const_str(collation_type, '?');
|
|
while (str_offset < str.length() && buf_offset + question_mark.length() <= buf_len) {
|
|
int64_t offset =
|
|
ObCharset::charpos(get_collation_type(), str.ptr() + str_offset, str.length() - str_offset, 1);
|
|
ret = ObCharset::charset_convert(get_collation_type(),
|
|
str.ptr() + str_offset,
|
|
offset,
|
|
collation_type,
|
|
buf + buf_offset,
|
|
buf_len - buf_offset,
|
|
result_len);
|
|
str_offset += offset;
|
|
if (OB_SUCCESS == ret) {
|
|
buf_offset += result_len;
|
|
} else {
|
|
MEMCPY(buf + buf_offset, question_mark.ptr(), question_mark.length());
|
|
buf_offset += question_mark.length();
|
|
}
|
|
}
|
|
if (str_offset < str.length()) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
LOG_WARN("size overflow", K(ret), K(str), KPHEX(str.ptr(), str.length()));
|
|
} else {
|
|
result_len = buf_offset;
|
|
ret = OB_SUCCESS;
|
|
LOG_WARN("charset convert failed", K(ret), K(get_collation_type()), K(collation_type));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
set_string(get_type(), buf, static_cast<int32_t>(result_len));
|
|
set_collation_type(collation_type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
DEFINE_SERIALIZE(ObObj)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
OB_UNIS_ENCODE(meta_);
|
|
if (OB_SUCC(ret)) {
|
|
if (meta_.is_invalid()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else {
|
|
ret = OBJ_FUNCS[meta_.get_type()].serialize(*this, buf, buf_len, pos);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
DEFINE_DESERIALIZE(ObObj)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
OB_UNIS_DECODE(meta_);
|
|
if (OB_SUCC(ret)) {
|
|
if (meta_.is_invalid()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else {
|
|
ret = OBJ_FUNCS[meta_.get_type()].deserialize(*this, buf, data_len, pos);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
DEFINE_GET_SERIALIZE_SIZE(ObObj)
|
|
{
|
|
int64_t len = 0;
|
|
OB_UNIS_ADD_LEN(meta_);
|
|
len += OBJ_FUNCS[meta_.get_type()].get_serialize_size(*this);
|
|
return len;
|
|
}
|
|
|
|
OB_SERIALIZE_MEMBER_INHERIT(ObObjParam, ObObj, accuracy_, res_flags_);
|
|
|
|
OB_SERIALIZE_MEMBER(ParamFlag, flag_);
|
|
|
|
void ObObjParam::reset()
|
|
{
|
|
accuracy_.reset();
|
|
res_flags_ = 0;
|
|
flag_.reset();
|
|
}
|
|
|
|
void ParamFlag::reset()
|
|
{
|
|
need_to_check_type_ = true;
|
|
need_to_check_bool_value_ = false;
|
|
expected_bool_value_ = false;
|
|
need_to_check_extend_type_ = true;
|
|
is_ref_cursor_type_ = false;
|
|
}
|
|
|
|
DEF_TO_STRING(ObHexEscapeSqlStr)
|
|
{
|
|
int64_t buf_pos = 0;
|
|
if (buf != NULL && buf_len > 0 && !str_.empty()) {
|
|
const char* end = str_.ptr() + str_.length();
|
|
if (lib::is_oracle_mode()) {
|
|
for (const char* cur = str_.ptr(); cur < end && buf_pos < buf_len; ++cur) {
|
|
if ('\'' == *cur) {
|
|
buf[buf_pos++] = '\'';
|
|
if (buf_pos < buf_len) {
|
|
buf[buf_pos++] = *cur;
|
|
}
|
|
} else {
|
|
buf[buf_pos++] = *cur;
|
|
}
|
|
}
|
|
} else {
|
|
for (const char* cur = str_.ptr(); cur < end && buf_pos < buf_len; ++cur) {
|
|
switch (*cur) {
|
|
case '\\': {
|
|
buf[buf_pos++] = '\\';
|
|
if (buf_pos < buf_len) {
|
|
buf[buf_pos++] = '\\';
|
|
}
|
|
break;
|
|
}
|
|
case '\0': {
|
|
buf[buf_pos++] = '\\';
|
|
if (buf_pos < buf_len) {
|
|
buf[buf_pos++] = '0';
|
|
}
|
|
break;
|
|
}
|
|
case '\'':
|
|
case '\"': {
|
|
buf[buf_pos++] = '\\';
|
|
if (buf_pos < buf_len) {
|
|
buf[buf_pos++] = *cur;
|
|
}
|
|
break;
|
|
}
|
|
case '\n': {
|
|
buf[buf_pos++] = '\\';
|
|
if (buf_pos < buf_len) {
|
|
buf[buf_pos++] = 'n';
|
|
}
|
|
break;
|
|
}
|
|
case '\r': {
|
|
buf[buf_pos++] = '\\';
|
|
if (buf_pos < buf_len) {
|
|
buf[buf_pos++] = 'r';
|
|
}
|
|
break;
|
|
}
|
|
case '\t': {
|
|
buf[buf_pos++] = '\\';
|
|
if (buf_pos < buf_len) {
|
|
buf[buf_pos++] = 't';
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
buf[buf_pos++] = *cur;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return buf_pos;
|
|
}
|
|
|
|
int64_t ObHexEscapeSqlStr::get_extra_length() const
|
|
{
|
|
int64_t ret_length = 0;
|
|
if (!str_.empty()) {
|
|
const char* end = str_.ptr() + str_.length();
|
|
if (lib::is_oracle_mode()) {
|
|
for (const char* cur = str_.ptr(); cur < end; ++cur) {
|
|
if ('\'' == *cur) {
|
|
++ret_length;
|
|
}
|
|
}
|
|
} else {
|
|
for (const char* cur = str_.ptr(); cur < end; ++cur) {
|
|
switch (*cur) {
|
|
case '\\':
|
|
case '\0':
|
|
case '\'':
|
|
case '\"':
|
|
case '\n':
|
|
case '\r':
|
|
case '\t': {
|
|
++ret_length;
|
|
break;
|
|
}
|
|
default: {
|
|
// do nothing
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret_length;
|
|
}
|