/** * 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 #include #include // 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(&version_)))) { COMMON_LOG(WARN, "fail to decode version", K(ret)); } else if (OB_FAIL(serialization::decode_i32(buf, buf_len, pos, reinterpret_cast(&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(&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(&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((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(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(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, obj_print_str, obj_print_plain_str, obj_print_json, \ obj_crc64, obj_crc64_v2, obj_batch_checksum, obj_murmurhash, \ ObjHashCalculator::calc_hash_value, obj_val_serialize, \ obj_val_deserialize, obj_val_get_serialize_size, \ ObjHashCalculator::calc_hash_value, obj_crc64_v3, \ ObjHashCalculator::calc_hash_value, \ ObjHashCalculator::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(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>\' ", 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(*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(*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& 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(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& 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(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& 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& 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(get_val_len()); } else { // get char length char_len = static_cast(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(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(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; }