提交 e88e59a6 编写于 作者: A AntiTopQuark 提交者: ob-robot

[CP] fix bug of weight_string

上级 ff557a58
......@@ -21,6 +21,8 @@
#include "lib/oblog/ob_log.h"
#include "sql/engine/expr/ob_datum_cast.h"
#include "ob_expr_util.h"
#include "sql/engine/ob_exec_context.h"
#include "sql/session/ob_sql_session_info.h"
using namespace oceanbase::common;
......@@ -46,20 +48,24 @@ int ObExprWeightString::calc_result_typeN(ObExprResType &type,
if (NOT_ROW_DIMENSION != row_dimension_ || ObMaxType == types_stack[0].get_type()) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
} else {
if (types_stack[0].get_type() > ObUNumberType ) {
// 输入不是数字类型时
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NULL_ON_WARN);
types_stack[0].set_calc_type(ObVarcharType);
}
int max_length = OB_MAX_VARBINARY_LENGTH; // The maximum length of the result of WEIGHT_STRING()
int result_length = types_stack[1].get_param().get_int();
int nweight = types_stack[2].get_param().get_int();
uint64_t max_length = OB_MAX_VARBINARY_LENGTH; // The maximum length of the result of WEIGHT_STRING()
uint64_t result_length = types_stack[1].get_param().get_int();
uint64_t nweight = types_stack[2].get_param().get_int();
bool as_binary = types_stack[4].get_param().get_int();
ObCollationLevel coll_level = CS_LEVEL_INVALID;
if (as_binary) {
coll_level = CS_LEVEL_IMPLICIT;
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NULL_ON_WARN);
types_stack[0].set_calc_type(ObVarcharType);
} else {
coll_level = types_stack[0].get_collation_level();
if (types_stack[0].get_type() > ObUNumberType &&
types_stack[0].get_type() != ObBitType &&
types_stack[0].get_type() != ObYearType) {
// When the input is not a numeric type, convert to a varchar type
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NULL_ON_WARN);
types_stack[0].set_calc_type(ObVarcharType);
}
}
ObCollationType collation_type = types_stack[0].get_collation_type();
const ObCharsetInfo *cs = ObCharset::get_charset(collation_type);
......@@ -67,19 +73,17 @@ int ObExprWeightString::calc_result_typeN(ObExprResType &type,
types_stack[0].get_type() == ObTimestampType ||
types_stack[0].get_type() == ObDateType ||
types_stack[0].get_type() == ObTimeType ) {
// 日期、时间等类型,max_lenght是输入的类型的长度
// For types such as date, time, etc., the max_lenght is the length of the type entered
max_length = types_stack[0].get_length();
} else if (result_length > 0) {
max_length = result_length;
} else if (as_binary) {
// as_binary的情况下,以nweight作为输出结果的max_length
// In the case of as_binary, the max_length with nweight as the output result
max_length = nweight;
} else {
// 输入为 char的情况下,使用cs->mbmaxlen计算max_length
max_length = cs->mbmaxlen * max(nweight, types_stack[0].get_length()*cs->mbmaxlen);
// If the input is others, use cs->mbmaxlen to calculate the max_length
max_length = cs->mbmaxlen * MAX(nweight, types_stack[0].get_length()*cs->mbmaxlen);
}
ObObj aaa = types_stack[0].get_param();
// 推导结果
type.set_varchar();
type.set_collation_type(CS_TYPE_BINARY);
type.set_collation_level(coll_level);
......@@ -105,44 +109,80 @@ int ObExprWeightString::calc_resultN(common::ObObj &result , const common::ObObj
result.set_null();
} else {
const ObString str = objs_array[0].get_string();
int result_length = objs_array[1].get_int();
int nweights = objs_array[2].get_int();
int flags = objs_array[3].get_int();
uint64_t result_length = objs_array[1].get_int();
uint64_t nweights = objs_array[2].get_int();
uint64_t flags = objs_array[3].get_int();
bool as_binary = objs_array[4].get_int();
ObCollationType collation_type = CS_TYPE_INVALID;
if (as_binary) {
collation_type = CS_TYPE_BINARY;
} else {
collation_type = objs_array[0].get_collation_type();
}
const ObCharsetInfo *cs = ObCharset::get_charset(collation_type);
flags = ob_strxfrm_flag_normalize(flags, cs->levels_for_order);
// calc the length of result
size_t frm_length = 0;
size_t tmp_length = 0;
if (result_length > 0) {
tmp_length = result_length;
} else {
tmp_length = cs->coll->strnxfrmlen(cs, cs->mbmaxlen*max(str.length() , nweights));
}
int is_valid_unicode_tmp = 1;
char *out_buf;
if (OB_ISNULL(out_buf = static_cast<char*>(expr_ctx.calc_buf_->alloc(tmp_length)))) {
int64_t max_allowed_packet = 0;
ObSQLSessionInfo *session = expr_ctx.exec_ctx_->get_my_session();
if (!as_binary && (objs_array[0].get_type() <= ObUNumberType ||
objs_array[0].get_type() == ObBitType ||
objs_array[0].get_type() == ObYearType)) {
result.set_null();
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("alloc memory failed",K(ret), K(out_buf), K(tmp_length));
} else if (str.empty() && nweights == 0) {
result.set_varchar(nullptr,0);
} else {
frm_length = cs->coll->strnxfrm(cs,
reinterpret_cast<uchar *>(out_buf),
tmp_length,
nweights ? nweights: tmp_length,
reinterpret_cast<const uchar *>(str.ptr()),
str.length(),
flags,
&is_valid_unicode_tmp);
result.set_varchar(out_buf,frm_length);
if (OB_FAIL(session->get_max_allowed_packet(max_allowed_packet))) {
if (OB_ENTRY_NOT_EXIST == ret) {
ret = OB_SUCCESS;
max_allowed_packet = OB_MAX_VARCHAR_LENGTH;
} else {
LOG_WARN("Failed to get max allow packet size", K(ret));
}
}
// Get the character set and collation information of the input string
ObCollationType collation_type = CS_TYPE_INVALID;
if (as_binary) {
collation_type = CS_TYPE_BINARY;
} else {
collation_type = objs_array[0].get_collation_type();
}
const ObCharsetInfo *cs = ObCharset::get_charset(collation_type);
flags = ob_strxfrm_flag_normalize(flags, cs->levels_for_order);
// calc the length of result
size_t frm_length = 0;
size_t tmp_length = 0;
if (result_length > 0) {
tmp_length = result_length;
} else {
tmp_length = cs->coll->strnxfrmlen(cs, cs->mbmaxlen*MAX(str.length() , nweights));
}
if (tmp_length >= max_allowed_packet) {
// The return result exceeds the maximum limit and returns NULL.
result.set_null();
} else {
int is_valid_unicode_tmp = 1;
// For the case where the input is an empty string but the nweight is not 0,
// the weight_string function will call strnxfrm() to padding the result
// eg:
// mysql> select HEX(WEIGHT_STRING('' as char(3)));
// +-----------------------------------+
// | HEX(WEIGHT_STRING('' as char(3))) |
// +-----------------------------------+
// | 002000200020 |
// +-----------------------------------+
// However, the strnxfrm requires that the input cannot be a null ptr,
// so an empty string is set as the input.
const char* tmp_empty_str = "";
char *out_buf;
if (OB_ISNULL(out_buf = static_cast<char*>(expr_ctx.calc_buf_->alloc(tmp_length)))) {
result.set_null();
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc output buf",K(ret));
} else {
frm_length = cs->coll->strnxfrm(cs,
reinterpret_cast<uchar *>(out_buf),
tmp_length,
nweights ? nweights: tmp_length,
str.ptr() != NULL? reinterpret_cast<const uchar *>(str.ptr()) : reinterpret_cast<const uchar *>(tmp_empty_str),
str.length(),
flags,
&is_valid_unicode_tmp);
result.set_varchar(out_buf,frm_length);
}
}
}
}
}
} else {
ret = OB_INVALID_ARGUMENT_NUM;
result.set_null();
......@@ -170,49 +210,81 @@ int ObExprWeightString::eval_weight_string(const ObExpr &expr, ObEvalCtx &ctx, O
KP(nweights_arg),
KP(flags_arg),
KP(as_binary_arg));
} else if (arg->is_null() ||
arg->get_string() == NULL ||
expr.args_[0]->datum_meta_.type_ <= ObUNumberType ) {
// The input string is NULL or numeric
res_datum.set_null();
} else {
const ObString str = arg->get_string();
int result_length = result_length_arg->get_int();
int nweights = nweights_arg->get_int();
int flags = flags_arg->get_int();
uint64_t result_length = result_length_arg->get_int();
uint64_t nweights = nweights_arg->get_int();
uint64_t flags = flags_arg->get_int();
bool as_binary = as_binary_arg->get_int();
// Get the character set and collation information of the input string
ObCollationType collation_type = CS_TYPE_INVALID;
if (as_binary) {
collation_type = CS_TYPE_BINARY;
int64_t max_allowed_packet = 0;
ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session();
if (arg->is_null()) {
res_datum.set_null();
} else if (!as_binary && (expr.args_[0]->datum_meta_.type_ <= ObUNumberType ||
expr.args_[0]->datum_meta_.type_ == ObBitType ||
expr.args_[0]->datum_meta_.type_ == ObYearType)) {
res_datum.set_null();
} else if (arg->get_string().empty() && nweights == 0) {
res_datum.set_string(nullptr,0);
} else {
collation_type = expr.args_[0]->datum_meta_.cs_type_;
}
const ObCharsetInfo *cs = ObCharset::get_charset(collation_type);
flags = ob_strxfrm_flag_normalize(flags, cs->levels_for_order);
// calc the length of result
size_t frm_length = 0;
size_t tmp_length = 0;
if (result_length > 0) {
tmp_length = result_length;
} else {
tmp_length = cs->coll->strnxfrmlen(cs, cs->mbmaxlen*max(str.length() , nweights));
}
int is_valid_unicode_tmp = 1;
char *out_buf = expr.get_str_res_mem(ctx, tmp_length);
if (OB_ISNULL(out_buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
} else {
frm_length = cs->coll->strnxfrm(cs,
reinterpret_cast<uchar *>(out_buf),
tmp_length,
nweights ? nweights: tmp_length,
reinterpret_cast<const uchar *>(str.ptr()),
str.length(),
flags,
&is_valid_unicode_tmp);
res_datum.set_string(out_buf,frm_length);
if (OB_FAIL(session->get_max_allowed_packet(max_allowed_packet))) {
if (OB_ENTRY_NOT_EXIST == ret) {
ret = OB_SUCCESS;
max_allowed_packet = OB_MAX_VARCHAR_LENGTH;
} else {
LOG_WARN("Failed to get max allow packet size", K(ret));
}
}
// Get the character set and collation information of the input string
ObCollationType collation_type = CS_TYPE_INVALID;
if (as_binary) {
collation_type = CS_TYPE_BINARY;
} else {
collation_type = expr.args_[0]->datum_meta_.cs_type_;
}
const ObCharsetInfo *cs = ObCharset::get_charset(collation_type);
flags = ob_strxfrm_flag_normalize(flags, cs->levels_for_order);
// calc the length of result
size_t frm_length = 0;
size_t tmp_length = 0;
if (result_length > 0) {
tmp_length = result_length;
} else {
tmp_length = cs->coll->strnxfrmlen(cs, cs->mbmaxlen*MAX(str.length() , nweights));
}
if (tmp_length >= max_allowed_packet) {
// The return result exceeds the maximum limit and returns NULL.
res_datum.set_null();
} else {
int is_valid_unicode_tmp = 1;
char *out_buf = expr.get_str_res_mem(ctx, tmp_length);
// For the case where the input is an empty string but the nweight is not 0,
// the weight_string function will call strnxfrm() to padding the result
// eg:
// mysql> select HEX(WEIGHT_STRING('' as char(3)));
// +-----------------------------------+
// | HEX(WEIGHT_STRING('' as char(3))) |
// +-----------------------------------+
// | 002000200020 |
// +-----------------------------------+
// However, the strnxfrm requires that the input cannot be a null ptr,
// so an empty string is set as the input.
const char* tmp_empty_str = "";
if (OB_ISNULL(out_buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc output buf",K(ret));
} else {
frm_length = cs->coll->strnxfrm(cs,
reinterpret_cast<uchar *>(out_buf),
tmp_length,
nweights ? nweights: tmp_length,
str.ptr() != NULL? reinterpret_cast<const uchar *>(str.ptr()) : reinterpret_cast<const uchar *>(tmp_empty_str),
str.length(),
flags,
&is_valid_unicode_tmp);
res_datum.set_string(out_buf,frm_length);
}
}
}
}
return ret;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册