488 lines
19 KiB
C++
488 lines
19 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 "ob_obj2str_helper.h"
|
|
#include "ob_log_timezone_info_getter.h"
|
|
#include "lib/timezone/ob_timezone_info.h"
|
|
#include "lib/string/ob_sql_string.h"
|
|
#include "sql/engine/expr/ob_datum_cast.h" // padding_char_for_cast
|
|
#include "lib/alloc/ob_malloc_allocator.h"
|
|
#include "sql/engine/expr/ob_expr_uuid.h"
|
|
#include "sql/engine/expr/ob_expr_operator.h"
|
|
#include "sql/engine/expr/ob_expr_res_type_map.h"
|
|
|
|
#include "ob_log_utils.h" // _M_
|
|
|
|
using namespace oceanbase::common;
|
|
namespace oceanbase
|
|
{
|
|
namespace liboblog
|
|
{
|
|
const char* ObObj2strHelper::EMPTY_STRING = "";
|
|
|
|
ObObj2strHelper::ObObj2strHelper() : inited_(false),
|
|
timezone_info_getter_(NULL),
|
|
hbase_util_(NULL),
|
|
enable_hbase_mode_(false),
|
|
enable_convert_timestamp_to_unix_timestamp_(false),
|
|
enable_backup_mode_(false),
|
|
tenant_mgr_(NULL)
|
|
{
|
|
}
|
|
|
|
ObObj2strHelper::~ObObj2strHelper()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
int ObObj2strHelper::init(IObLogTimeZoneInfoGetter &timezone_info_getter,
|
|
ObLogHbaseUtil &hbase_util,
|
|
const bool enable_hbase_mode,
|
|
const bool enable_convert_timestamp_to_unix_timestamp,
|
|
const bool enable_backup_mode,
|
|
IObLogTenantMgr &tenant_mgr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (inited_) {
|
|
ret = OB_INIT_TWICE;
|
|
} else if (OB_FAIL(init_ob_charset_utils())) {
|
|
OBLOG_LOG(ERROR, "failed to init ob charset util!", KR(ret));
|
|
} else {
|
|
timezone_info_getter_ = &timezone_info_getter;
|
|
hbase_util_ = &hbase_util;
|
|
enable_hbase_mode_ = enable_hbase_mode;
|
|
enable_convert_timestamp_to_unix_timestamp_ = enable_convert_timestamp_to_unix_timestamp;
|
|
enable_backup_mode_ = enable_backup_mode;
|
|
tenant_mgr_ = &tenant_mgr;
|
|
inited_ = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObObj2strHelper::init_ob_charset_utils()
|
|
{
|
|
int ret = common::OB_SUCCESS;
|
|
lib::ObMallocAllocator *allocator = NULL;
|
|
const lib::ObMemAttr attr(common::OB_SYS_TENANT_ID, ObModIds::OB_NUMBER);
|
|
if (OB_FAIL(sql::ObExprTRDateFormat::init())) {
|
|
OBLOG_LOG(ERROR, "failed to init vars in oracle trunc", KR(ret));
|
|
} else if (OB_FAIL(sql::ObExprUuid::init())) {
|
|
OBLOG_LOG(ERROR, "failed to init vars in uuid", KR(ret));
|
|
} else if (OB_ISNULL(allocator = lib::ObMallocAllocator::get_instance())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
OBLOG_LOG(ERROR, "allocator is null", KR(ret));
|
|
} else if (OB_FAIL(common::ObNumberConstValue::init(*allocator, attr))) {
|
|
OBLOG_LOG(ERROR, "failed to init ObNumberConstValue", KR(ret));
|
|
} else if (OB_FAIL(sql::ARITH_RESULT_TYPE_ORACLE.init())) {
|
|
OBLOG_LOG(ERROR, "failed to init ORACLE_ARITH_RESULT_TYPE", KR(ret));
|
|
} else if (OB_FAIL(ObCharsetUtils::init(*allocator))) {
|
|
OBLOG_LOG(ERROR, "fail to init ObCharsetUtils", KR(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObObj2strHelper::destroy()
|
|
{
|
|
inited_ = false;
|
|
timezone_info_getter_ = NULL;
|
|
hbase_util_ = NULL;
|
|
enable_hbase_mode_ = false;
|
|
enable_convert_timestamp_to_unix_timestamp_ = false;
|
|
enable_backup_mode_ = false;
|
|
tenant_mgr_ = NULL;
|
|
}
|
|
|
|
|
|
//extended_type_info used for enum/set
|
|
int ObObj2strHelper::obj2str(const uint64_t tenant_id,
|
|
const uint64_t table_id,
|
|
const uint64_t column_id,
|
|
const common::ObObj &obj,
|
|
common::ObString &str,
|
|
common::ObIAllocator &allocator,
|
|
const bool string_deep_copy,
|
|
const common::ObIArray<common::ObString> &extended_type_info,
|
|
const common::ObAccuracy &accuracy,
|
|
const common::ObCollationType &collation_type)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObObjType obj_type = obj.get_type();
|
|
common::ObObjTypeClass obj_tc = common::ob_obj_type_class(obj_type);
|
|
ObWorker::CompatMode compat_mode = THIS_WORKER.get_compatibility_mode();
|
|
|
|
// Configure allowed conversions: mysql timestamp column -> UTC integer time
|
|
if (ObTimestampType == obj_type && enable_convert_timestamp_to_unix_timestamp_) {
|
|
if (OB_FAIL(convert_mysql_timestamp_to_utc_(obj, str, allocator))) {
|
|
OBLOG_LOG(ERROR, "convert_mysql_timestamp_to_utc_ fail", KR(ret), K(table_id), K(column_id), K(obj), K(obj_type),
|
|
K(str));
|
|
}
|
|
} else if (common::ObNullTC == obj_tc) {
|
|
str.assign_ptr(NULL, 0);
|
|
} else if (common::ObExtendTC == obj_tc) {
|
|
static const int64_t MAX_EXT_PRINT_LEN = 1 << 10;
|
|
char BUFFER[MAX_EXT_PRINT_LEN];
|
|
int64_t pos = 0;
|
|
char *ptr = NULL;
|
|
|
|
if (OB_FAIL(obj.print_sql_literal(BUFFER, sizeof(BUFFER), pos))
|
|
|| pos <= 0) {
|
|
OBLOG_LOG(ERROR, "obj print_sql_literal fail", KR(ret), K(obj), K(MAX_EXT_PRINT_LEN), K(pos));
|
|
ret = common::OB_SUCCESS == ret ? common::OB_ERR_UNEXPECTED : ret;
|
|
} else if (NULL == (ptr = (char *)allocator.alloc(pos))) {
|
|
OBLOG_LOG(ERROR, "allocate memory fail", "size", pos);
|
|
ret = common::OB_ALLOCATE_MEMORY_FAILED;
|
|
} else {
|
|
(void)MEMCPY(ptr, BUFFER, pos);
|
|
str.assign_ptr(ptr, (int32_t)pos);
|
|
OBLOG_LOG(DEBUG, "obj2str cast extend type", K(obj), "cast_str", str);
|
|
}
|
|
// This should be before is_string_type, because for char/nchar it is also ObStringTC, so is_string_type=true
|
|
} else if (need_padding_(compat_mode, obj)) {
|
|
if (OB_FAIL(convert_char_obj_to_padding_obj_(compat_mode, obj, accuracy, collation_type, allocator, str))) {
|
|
OBLOG_LOG(ERROR, "convert_char_obj_to_padding_obj_ fail", KR(ret), K(obj), K(accuracy), K(collation_type),
|
|
K(str), K(compat_mode), "compat_mode_str", print_compat_mode(compat_mode));
|
|
}
|
|
} else if (obj.is_string_type()) {
|
|
if (string_deep_copy) {
|
|
// need deep-copy
|
|
void *dst_buf = NULL;
|
|
ObString src_str = obj.get_string();
|
|
int64_t str_len = obj.get_val_len();
|
|
|
|
if (str_len > 0) {
|
|
if (OB_ISNULL(dst_buf = allocator.alloc(str_len))) {
|
|
OBLOG_LOG(ERROR, "allocate memory fail", K(str_len));
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
} else {
|
|
MEMCPY(dst_buf, src_str.ptr(), src_str.length());
|
|
}
|
|
}
|
|
|
|
if (OB_SUCCESS == ret) {
|
|
str.assign_ptr(static_cast<char *>(dst_buf),
|
|
static_cast<ObString::obstr_size_t>(str_len));
|
|
}
|
|
} else {
|
|
// No deep copy required, direct reference to original string memory
|
|
if (OB_FAIL(obj.get_string(str))) {
|
|
OBLOG_LOG(ERROR, "get_string from ObObj fail", KR(ret), K(obj));
|
|
} else {
|
|
// success
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
// For a varchar with a default value of '', str_len=0, the empty string should be synchronised and not output as NULL
|
|
if (0 == obj.get_val_len()) {
|
|
str.assign_ptr(EMPTY_STRING, static_cast<ObString::obstr_size_t>(obj.get_val_len()));
|
|
}
|
|
}
|
|
} else {
|
|
common::ObObj tmp_inner_obj;
|
|
const common::ObObj *in_obj = &obj;
|
|
ObObjMeta inner_meta;
|
|
inner_meta.set_collation_level(CS_LEVEL_NUMERIC);
|
|
inner_meta.set_collation_type(CS_TYPE_BINARY);
|
|
if (obj.is_enum() || obj.is_set()) {
|
|
if (OB_FAIL(ObObjCaster::enumset_to_inner(inner_meta, obj, tmp_inner_obj,
|
|
allocator, extended_type_info))) {
|
|
OBLOG_LOG(ERROR, "fail to enumset_to_inner", KR(ret));
|
|
} else {
|
|
in_obj = &tmp_inner_obj;
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
common::ObObj str_obj;
|
|
common::ObObjType target_type = common::ObMaxType;
|
|
|
|
//liboblog need use_standard_format
|
|
ObTimeZoneInfoWrap *tz_info_wrap = nullptr;
|
|
const common::ObTimeZoneInfo *tz_info = nullptr;
|
|
if (OB_FAIL(tenant_mgr_->get_tenant_tz_wrap(tenant_id, tz_info_wrap))) {
|
|
OBLOG_LOG(ERROR, "get_tenant_tz_wrap failed", KR(ret), K(tenant_id));
|
|
} else if (OB_ISNULL(tz_info_wrap)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
OBLOG_LOG(ERROR, "tenant not exist", KR(ret), K(tenant_id));
|
|
} else {
|
|
tz_info = tz_info_wrap->get_time_zone_info();
|
|
const ObDataTypeCastParams dtc_params(tz_info);
|
|
ObObjCastParams cast_param(&allocator, &dtc_params, CM_NONE, collation_type);
|
|
cast_param.format_number_with_limit_ = false;//here need no limit format number for liboblog
|
|
|
|
if (in_obj->is_bit()) {
|
|
target_type = common::ObUInt64Type;
|
|
} else {
|
|
target_type = common::ObVarcharType;
|
|
}
|
|
|
|
if (OB_FAIL(ObObjCaster::to_type(target_type, cast_param, *in_obj, str_obj))) {
|
|
OBLOG_LOG(ERROR, "cast obj to varchar type fail", KR(ret), KPC(in_obj), K(target_type));
|
|
if (OB_ERR_INVALID_TIMEZONE_REGION_ID == ret) {
|
|
// Refresh timezone until successful and convert again
|
|
ret = OB_SUCCESS;
|
|
|
|
if (OB_FAIL(convert_timestamp_with_timezone_data_util_succ_(target_type, cast_param,
|
|
*in_obj, str_obj, str, tenant_id))) {
|
|
OBLOG_LOG(ERROR, "convert_timestamp_with_timezone_data_util_succ_ fail", KR(ret), KPC(in_obj), K(target_type));
|
|
}
|
|
}
|
|
} else {
|
|
if (in_obj->is_bit()) {
|
|
if (OB_FAIL(convert_bit_obj_to_decimal_str_(obj, str_obj, str, allocator))) {
|
|
OBLOG_LOG(ERROR, "convert_bit_obj_to_decimal_str_ fail", KR(ret), K(obj), K(target_type));
|
|
}
|
|
} else {
|
|
if (OB_FAIL(str_obj.get_string(str))) {
|
|
OBLOG_LOG(ERROR, "get_string from ObObj fail", KR(ret), K(str_obj));
|
|
} else {
|
|
// For a varchar with a default value of '', str_len=0, the empty string should be synchronised and not output as NULL
|
|
if ((obj.is_enum() || obj.is_set()) && 0 == str_obj.get_val_len()) {
|
|
str.assign_ptr(EMPTY_STRING, static_cast<ObString::obstr_size_t>(str_obj.get_val_len()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1. hbase table T column timestamp type should be converted to positive if it is negative
|
|
// 2. not converted in backup mode
|
|
if (OB_SUCC(ret)) {
|
|
bool is_hbase_table_T_column = false;
|
|
|
|
if (obj.is_int() && enable_hbase_mode_ && ! enable_backup_mode_) {
|
|
if (OB_ISNULL(hbase_util_)) {
|
|
OBLOG_LOG(ERROR, "hbase_util_ is null", K(hbase_util_));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else if (OB_FAIL(hbase_util_->judge_hbase_T_column(table_id, column_id, is_hbase_table_T_column))) {
|
|
OBLOG_LOG(ERROR, "hbase_util_ judge_hbase_T_column fail", KR(ret), K(table_id), K(column_id), K(is_hbase_table_T_column));
|
|
} else if (! is_hbase_table_T_column) {
|
|
// do nothing
|
|
} else {
|
|
if (OB_FAIL(convert_hbase_bit_obj_to_positive_bit_str_(obj, str_obj, str, allocator))) {
|
|
OBLOG_LOG(ERROR, "convert_hbase_bit_obj_to_positive_bit_str_ fail", KR(ret), K(obj), K(target_type));
|
|
}
|
|
}
|
|
}
|
|
OBLOG_LOG(DEBUG, "[HBASE]", KR(ret), K(obj), K(obj_type), K(enable_hbase_mode_), K(enable_backup_mode_),
|
|
K(str_obj), K(is_hbase_table_T_column), K(table_id));
|
|
}
|
|
} // OB_SUCC(ret)
|
|
}
|
|
|
|
// If it is a LOB, larger than 2M, do not print the contents, print the address and length
|
|
// Avoid printing the log taking too long
|
|
if (str.length() > 2 * _M_) {
|
|
OBLOG_LOG(DEBUG, "obj2str", KR(ret), K(obj_type), K(obj.get_scale()), K(obj.get_meta()), K(obj_tc), K(accuracy), K(collation_type),
|
|
KP(obj.get_string().ptr()), K(obj.get_string().length()), KP(str.ptr()), K(str.length()));
|
|
} else {
|
|
OBLOG_LOG(DEBUG, "obj2str", KR(ret), K(obj_type), K(obj.get_scale()), K(obj.get_meta()), K(obj_tc), K(accuracy), K(collation_type),
|
|
K(obj), K(str), K(str.length()));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObObj2strHelper::convert_timestamp_with_timezone_data_util_succ_(const common::ObObjType &target_type,
|
|
common::ObObjCastParams &cast_param,
|
|
const common::ObObj &in_obj,
|
|
common::ObObj &str_obj,
|
|
common::ObString &str,
|
|
const uint64_t tenant_id)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool done = false;
|
|
ObTZInfoMap *tz_info_map = NULL;
|
|
|
|
if (OB_ISNULL(timezone_info_getter_)) {
|
|
OBLOG_LOG(ERROR, "timezone_info_getter_ is null", K(timezone_info_getter_));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else if (OB_FAIL(tenant_mgr_->get_tenant_tz_map(tenant_id, tz_info_map))) {
|
|
OBLOG_LOG(ERROR, "get_tenant_tz_map failed", KR(ret), K(tenant_id));
|
|
} else {
|
|
while (! done && OB_SUCCESS == ret) {
|
|
if (OB_FAIL(timezone_info_getter_->fetch_tenant_timezone_info_util_succ(tenant_id, tz_info_map))) {
|
|
OBLOG_LOG(ERROR, "fetch_tenant_timezone_info_util_succ fail", KR(ret), K(tenant_id));
|
|
} else if (OB_FAIL(ObObjCaster::to_type(target_type, cast_param, in_obj, str_obj))) {
|
|
if (OB_ERR_INVALID_TIMEZONE_REGION_ID == ret) {
|
|
OBLOG_LOG(WARN, "cast obj to varchar type fail, try again", KR(ret), K(in_obj), K(target_type));
|
|
} else {
|
|
OBLOG_LOG(ERROR, "cast obj to varchar type fail", KR(ret), K(in_obj), K(target_type));
|
|
}
|
|
} else {
|
|
done = true;
|
|
if (OB_FAIL(str_obj.get_string(str))) {
|
|
OBLOG_LOG(ERROR, "get_string from ObObj fail", KR(ret), K(str_obj));
|
|
}
|
|
}
|
|
|
|
if (OB_ERR_INVALID_TIMEZONE_REGION_ID == ret) {
|
|
ret = OB_SUCCESS;
|
|
usleep(10L * 1000L);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// bit type output decimal string
|
|
int ObObj2strHelper::convert_bit_obj_to_decimal_str_(const common::ObObj &obj,
|
|
const common::ObObj &str_obj,
|
|
common::ObString &str,
|
|
common::ObIAllocator &allocator)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
uint64_t value = 0;
|
|
|
|
if (OB_FAIL(str_obj.get_uint64(value))) {
|
|
OBLOG_LOG(ERROR, "get_uint64 from ObObj fail", KR(ret), K(obj), K(str_obj), K(value));
|
|
} else {
|
|
char buf[MAX_BIT_DECIMAL_STR_LENGTH];
|
|
int64_t pos = 0;
|
|
char *ptr = NULL;
|
|
|
|
if (OB_FAIL(common::databuff_printf(buf, MAX_BIT_DECIMAL_STR_LENGTH, pos, "%lu", value))) {
|
|
OBLOG_LOG(ERROR, "databuff_printf fail", K(pos), K(value));
|
|
} else if (OB_ISNULL(ptr = (char *)allocator.alloc(pos))) {
|
|
OBLOG_LOG(ERROR, "allocate memory fail", "size", pos);
|
|
ret = common::OB_ALLOCATE_MEMORY_FAILED;
|
|
} else {
|
|
(void)MEMCPY(ptr, buf, pos);
|
|
str.assign_ptr(ptr, (int32_t)pos);
|
|
OBLOG_LOG(DEBUG, "obj2str cast bit type", K(obj), "cast_str", str, K(value));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObObj2strHelper::convert_hbase_bit_obj_to_positive_bit_str_(const common::ObObj &obj,
|
|
const common::ObObj ¤t_str_obj,
|
|
common::ObString &str,
|
|
common::ObIAllocator &allocator)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
UNUSED(allocator);
|
|
|
|
ObString current_str;
|
|
const char *current_str_ptr = NULL;
|
|
ObString::obstr_size_t current_str_len = 0;
|
|
|
|
if (OB_FAIL(current_str_obj.get_string(current_str))) {
|
|
OBLOG_LOG(ERROR, "get_string from ObObj fail", KR(ret), K(obj), K(current_str_obj), K(current_str));
|
|
} else if (OB_ISNULL(current_str_ptr = current_str.ptr())) {
|
|
OBLOG_LOG(ERROR, "current_str_ptr is null", K(obj), K(current_str_obj), K(current_str), K(current_str_ptr));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else {
|
|
current_str_len = current_str.length();
|
|
OBLOG_LOG(DEBUG, "[HBASE]", K(obj), K(current_str_obj), K(current_str), K(current_str_ptr), K(current_str_len));
|
|
|
|
if ('-' == current_str_ptr[0]) {
|
|
str.assign_ptr(current_str_ptr + 1, (int32_t)(current_str_len - 1));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObObj2strHelper::convert_mysql_timestamp_to_utc_(const common::ObObj &obj,
|
|
common::ObString &str,
|
|
common::ObIAllocator &allocator)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const int64_t utc_time = obj.get_timestamp();
|
|
char buf[MAX_TIMESTAMP_UTC_LONG_STR_LENGTH];
|
|
int64_t pos = 0;
|
|
char *ptr = NULL;
|
|
// external output of utc integer time, compatible with mysql, splitting seconds and microseconds with a decimal point
|
|
// Microsecond precision length of 6
|
|
const int64_t usec_mod_val = 1000000;
|
|
|
|
if (OB_FAIL(common::databuff_printf(buf, MAX_TIMESTAMP_UTC_LONG_STR_LENGTH, pos, "%ld.%06ld",
|
|
utc_time / usec_mod_val, utc_time % usec_mod_val))) {
|
|
OBLOG_LOG(ERROR, "databuff_printf fail", K(pos), K(utc_time), K(usec_mod_val));
|
|
} else if (OB_ISNULL(ptr = (char *)allocator.alloc(pos))) {
|
|
OBLOG_LOG(ERROR, "allocate memory fail", "size", pos);
|
|
ret = common::OB_ALLOCATE_MEMORY_FAILED;
|
|
} else {
|
|
(void)MEMCPY(ptr, buf, pos);
|
|
str.assign_ptr(ptr, (int32_t)pos);
|
|
OBLOG_LOG(DEBUG, "obj2str cast timestamp type to utc long", K(obj), "cast_str", str, K(utc_time));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool ObObj2strHelper::need_padding_(const ObWorker::CompatMode &compat_mode,
|
|
const common::ObObj &obj) const
|
|
{
|
|
bool bool_ret = false;
|
|
|
|
bool_ret = (ObWorker::CompatMode::ORACLE == compat_mode)
|
|
&& (obj.is_char() || obj.is_nchar());
|
|
|
|
return bool_ret;
|
|
}
|
|
|
|
int ObObj2strHelper::convert_char_obj_to_padding_obj_(const ObWorker::CompatMode &compat_mode,
|
|
const common::ObObj &obj,
|
|
const common::ObAccuracy &accuracy,
|
|
const common::ObCollationType &collation_type,
|
|
common::ObIAllocator &allocator,
|
|
common::ObString &str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int32_t char_len = 0;
|
|
|
|
if (OB_FAIL(obj.get_string(str))) {
|
|
OBLOG_LOG(ERROR, "get_string from ObObj fail", KR(ret), K(obj));
|
|
} else if (OB_FAIL(obj.get_char_length(accuracy, char_len, ObWorker::CompatMode::ORACLE == compat_mode))) {
|
|
OBLOG_LOG(ERROR, "obj get_char_length fail", KR(ret), K(accuracy), K(char_len));
|
|
} else {
|
|
// The calculation of padding here needs to be based on char_len, not str.length
|
|
// e.g. nchar, 'a', str,length=2, not 1
|
|
const int64_t padding_cnt = accuracy.get_length() - char_len;
|
|
// need pad
|
|
if (padding_cnt > 0) {
|
|
ObString padding_res;
|
|
|
|
if (OB_FAIL(sql::padding_char_for_cast(padding_cnt, collation_type, allocator, padding_res))) {
|
|
OBLOG_LOG(ERROR, "padding_char_for_cast fail", KR(ret), K(obj), K(accuracy), K(collation_type),
|
|
K(padding_res));
|
|
} else {
|
|
int64_t all_size = padding_res.length() + str.length();
|
|
char *res_ptr = static_cast<char*>(allocator.alloc(all_size));
|
|
|
|
if (OB_ISNULL(res_ptr)) {
|
|
OBLOG_LOG(ERROR, "allocate memory failed", KR(ret));
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
} else {
|
|
MEMMOVE(res_ptr, str.ptr(), str.length());
|
|
MEMMOVE(res_ptr + str.length(), padding_res.ptr(), padding_res.length());
|
|
str.assign_ptr(res_ptr, static_cast<ObString::obstr_size_t>(all_size));
|
|
|
|
OBLOG_LOG(DEBUG, "obj2str cast char/nchar type", K(obj), "cast_str", str, "cast_str_len", str.length(),
|
|
K(padding_cnt), K(padding_res), "padding_res_len", padding_res.length(),
|
|
K(accuracy), K(collation_type), K(char_len));
|
|
}
|
|
}
|
|
} // if (padding_cnt > 0)
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
} // namespace liboblog
|
|
} // namespace oceanbase
|