patch 4.0

This commit is contained in:
wangzelin.wzl
2022-10-24 10:34:53 +08:00
parent 4ad6e00ec3
commit 93a1074b0c
10533 changed files with 2588271 additions and 2299373 deletions

View File

@ -15,29 +15,38 @@
#include "lib/oblog/ob_log.h"
#include "share/object/ob_obj_cast.h"
#include "sql/engine/expr/ob_expr_substr.h"
#include "sql/parser/ob_item_type.h"
#include "objit/common/ob_item_type.h"
#include "sql/engine/expr/ob_expr_util.h"
#include "sql/session/ob_sql_session_info.h"
#include "storage/ob_storage_util.h"
namespace oceanbase {
namespace oceanbase
{
using namespace common;
namespace sql {
namespace sql
{
ObExprSubstr::ObExprSubstr(ObIAllocator& alloc) : ObStringExprOperator(alloc, T_FUN_SYS_SUBSTR, N_SUBSTR, TWO_OR_THREE)
{}
ObExprSubstr::ObExprSubstr(ObIAllocator &alloc)
: ObStringExprOperator(alloc, T_FUN_SYS_SUBSTR, N_SUBSTR, TWO_OR_THREE)
{
}
ObExprSubstr::~ObExprSubstr()
{}
{
}
int ObExprSubstr::calc_result_length(
ObExprResType* types_array, int64_t param_num, ObCollationType cs_type, int64_t& res_len) const
//计算substr结果的长度
int ObExprSubstr::calc_result_length(ObExprResType *types_array,
int64_t param_num,
ObCollationType cs_type,
int64_t &res_len) const
{
int ret = OB_SUCCESS;
ObString str_text;
int64_t start_pos = 1;
int64_t result_len = types_array[0].get_length();
int64_t result_len = types_array[0].get_length(); //最大长度
int64_t substr_len = result_len;
const bool is_oracle_mode = share::is_oracle_mode();
const bool is_oracle_mode = lib::is_oracle_mode();
ObExprCtx expr_ctx;
ObArenaAllocator allocator(common::ObModIds::OB_SQL_EXPR_CALC);
expr_ctx.calc_buf_ = &allocator;
@ -46,7 +55,7 @@ int ObExprSubstr::calc_result_length(
ret = OB_INVALID_ARGUMENT;
LOG_WARN("substr should have two or three arguments", K(param_num), K(ret));
} else {
const ObObj start_obj = types_array[1].get_param();
const ObObj &start_obj = types_array[1].get_param();
if (!start_obj.is_null()) {
if (is_oracle_mode) {
if (OB_FAIL(ObExprUtil::get_trunc_int64(start_obj, expr_ctx, start_pos))) {
@ -60,8 +69,8 @@ int ObExprSubstr::calc_result_length(
start_pos = start_obj.get_int();
}
}
if (OB_SUCC(ret) && param_num == 3 && !types_array[2].get_param().is_null()) {
const ObObj len_obj = types_array[2].get_param();
if (OB_SUCC(ret) && 3 == param_num && !types_array[2].get_param().is_null()) {
const ObObj &len_obj = types_array[2].get_param();
if (is_oracle_mode && OB_FAIL(ObExprUtil::get_trunc_int64(len_obj, expr_ctx, substr_len))) {
ret = OB_SUCCESS;
LOG_WARN("ignore failure when calc result type length oracle mode", K(ret));
@ -75,7 +84,8 @@ int ObExprSubstr::calc_result_length(
if (0 >= result_len || 0 >= substr_len || start_pos > result_len) {
res_len = 0;
} else {
const ObObj text_obj = types_array[0].get_param();
const ObObj &text_obj = types_array[0].get_param();
//根据参数0是否为常量区别计算
if (ob_is_string_type(text_obj.get_type()) && OB_SUCC(text_obj.get_string(str_text))) {
int64_t mb_len = ObCharset::strlen_char(cs_type, str_text.ptr(), str_text.length());
start_pos = (start_pos >= 0) ? start_pos - 1 : start_pos + mb_len;
@ -84,15 +94,12 @@ int ObExprSubstr::calc_result_length(
} else {
res_len = min(substr_len, mb_len - start_pos);
int64_t offset = ObCharset::charpos(cs_type, str_text.ptr(), str_text.length(), start_pos);
res_len = ObCharset::charpos(cs_type,
str_text.ptr() + offset,
(offset == 0) ? str_text.length() : str_text.length() - offset + 1,
res_len);
res_len = ObCharset::charpos(cs_type, str_text.ptr() + offset,
(offset == 0) ? str_text.length() : str_text.length() - offset + 1, res_len);
}
} else {
int64_t mbmaxlen = 0;
if (OB_FAIL(ObCharset::get_mbmaxlen_by_coll(cs_type, mbmaxlen))) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "fail to get mbmaxlen", K(ret), K(cs_type));
} else if (0 == mbmaxlen) {
ret = OB_ERR_UNEXPECTED;
@ -128,66 +135,142 @@ int ObExprSubstr::calc_result_length(
return ret;
}
int ObExprSubstr::calc_result_typeN(
ObExprResType& type, ObExprResType* types_array, int64_t param_num, ObExprTypeCtx& type_ctx) const
int ObExprSubstr::calc_result_length_oracle(const ObExprResType *types_array,
int64_t param_num,
const ObExprResType &result_type,
int64_t &res_len) const
{
int ret = OB_SUCCESS;
CK(NULL != type_ctx.get_session());
CK(2 == param_num || 3 == param_num);
if (lib::is_oracle_mode()) {
bool prefer_varchar = true;
auto str_params = make_const_carray(&types_array[0]);
OZ(aggregate_string_type_and_charset_oracle(*type_ctx.get_session(), str_params, type, prefer_varchar));
OZ(deduce_string_param_calc_type_and_charset(*type_ctx.get_session(), type, str_params));
for (int i = 1; i < param_num; i++) {
types_array[i].set_calc_type(ObNumberType);
types_array[i].set_calc_scale(NUMBER_SCALE_UNKNOWN_YET);
ObString str_text;
int64_t start_pos = 1;
int64_t result_len = types_array[0].get_calc_length(); //最大长度
int64_t substr_len = result_len;
ObExprCtx expr_ctx;
ObArenaAllocator allocator(common::ObModIds::OB_SQL_EXPR_CALC);
expr_ctx.calc_buf_ = &allocator;
res_len = result_len;
const ObObj start_obj = types_array[1].get_param();
if (!start_obj.is_null()) {
if (OB_FAIL(ObExprUtil::get_trunc_int64(start_obj, expr_ctx, start_pos))) {
ret = OB_SUCCESS;
LOG_WARN("ignore failure when calc result type length oracle mode", K(ret));
}
} else {
type.set_varchar();
OZ(aggregate_charsets_for_string_result(type, types_array, 1, type_ctx.get_coll_type()));
types_array[0].set_calc_type(type.get_type());
types_array[0].set_calc_collation_level(type.get_calc_collation_level());
types_array[0].set_calc_collation_type(type.get_collation_type());
if (OB_SUCC(ret)) {
if (type_ctx.get_session()->use_static_typing_engine()) {
for (int i = 1; i < param_num; i++) {
types_array[i].set_calc_type(ObIntType);
}
if (0 == start_pos) {
start_pos = 1;
}
}
if (OB_SUCC(ret) && 3 == param_num && !types_array[2].get_param().is_null()) {
const ObObj len_obj = types_array[2].get_param();
if (OB_FAIL(ObExprUtil::get_trunc_int64(len_obj, expr_ctx, substr_len))) {
ret = OB_SUCCESS;
LOG_WARN("ignore failure when calc result type length oracle mode", K(ret));
}
}
if (OB_SUCC(ret)) {
LOG_DEBUG("substr calc len", K(result_len), K(substr_len), K(start_pos));
if (0 >= result_len || 0 >= substr_len || start_pos > result_len) {
res_len = 0;
} else {
int64_t mbmaxlen = 0;
ObCollationType cs_type = result_type.get_collation_type();
if (OB_FAIL(ObCharset::get_mbmaxlen_by_coll(cs_type, mbmaxlen))) {
SQL_RESV_LOG(WARN, "fail to get mbmaxlen", K(ret), K(cs_type));
} else {
for (int i = 1; i < param_num; i++) {
types_array[i].set_calc_type(types_array[i].get_type());
if (start_pos > 0 && substr_len > 0) {
if (start_pos + substr_len <= result_len + 1) {
res_len = substr_len;
} else {
res_len = result_len - start_pos + 1;
}
if (result_type.is_varchar_or_char() && LS_BYTE == result_type.get_length_semantics()) {
res_len *= mbmaxlen;
}
}
}
}
// Set cast mode for integer parameters, truncate string to integer.
// see: ObExprSubstr::cast_param_type_for_mysql
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_STRING_INTEGER_TRUNC);
}
// deduce max length.
int64_t len = types_array[0].get_length();
OZ(calc_result_length(types_array, param_num, type.get_collation_type(), len));
CK(len <= INT32_MAX);
if (OB_SUCC(ret)) {
type.set_length(static_cast<ObLength>(len));
}
return ret;
}
int ObExprSubstr::calc_result_typeN(ObExprResType &type,
ObExprResType *types_array,
int64_t param_num,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
int64_t len = 0;
CK(NULL != type_ctx.get_session());
CK(2 == param_num || 3 == param_num);
if (lib::is_oracle_mode()) {
auto str_params = make_const_carray(&types_array[0]);
OZ(aggregate_string_type_and_charset_oracle(*type_ctx.get_session(),
str_params,
type,
PREFER_VAR_LEN_CHAR));
OZ(deduce_string_param_calc_type_and_charset(*type_ctx.get_session(), type, str_params));
for (int i = 1; OB_SUCC(ret) && i < param_num; i++) {
types_array[i].set_calc_type(ObNumberType);
types_array[i].set_calc_scale(NUMBER_SCALE_UNKNOWN_YET);
}
OZ(calc_result_length_oracle(types_array, param_num, type, len));
CK(len <= INT32_MAX);
OX(type.set_length(static_cast<ObLength>(len)));
} else {
const int32_t mbmaxlen = 4;
if (ObTextType == types_array[0].get_type()
|| ObMediumTextType == types_array[0].get_type()
|| ObLongTextType == types_array[0].get_type()) {
type.set_type(ObLongTextType);
type.set_length(OB_MAX_LONGTEXT_LENGTH / mbmaxlen);
} else if (ObTinyTextType == types_array[0].get_type()) {
type.set_type(ObTextType);
type.set_length(OB_MAX_TEXT_LENGTH / mbmaxlen);
} else {
type.set_varchar();
}
OZ(aggregate_charsets_for_string_result(type, types_array, 1, type_ctx.get_coll_type()));
if (OB_SUCC(ret)) {
if (is_mysql_mode() && (types_array[0].is_text() || types_array[0].is_blob())) {
// do nothing
} else {
types_array[0].set_calc_type(ObVarcharType);
}
types_array[0].set_calc_collation_level(type.get_calc_collation_level());
types_array[0].set_calc_collation_type(type.get_collation_type());
}
if (OB_SUCC(ret)) {
for (int i = 1; i < param_num; i++) {
types_array[i].set_calc_type(ObIntType);
}
}
if (OB_SUCC(ret) && type.is_varchar()) {
// Set cast mode for integer parameters, truncate string to integer.
// see: ObExprSubstr::cast_param_type_for_mysql
OX(type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_STRING_INTEGER_TRUNC));
OX(len = types_array[0].get_length());
// deduce max length.
OZ(calc_result_length(types_array, param_num, type.get_collation_type(), len));
CK(len <= INT32_MAX);
OX(type.set_length(static_cast<ObLength>(len)));
}
}
return ret;
}
// to make "select substr('abcd', '1.9')" compatible with mysql
int ObExprSubstr::cast_param_type_for_mysql(const ObObj& in, ObExprCtx& expr_ctx, ObObj& out) const
int ObExprSubstr::cast_param_type_for_mysql(const ObObj& in,
ObExprCtx& expr_ctx,
ObObj& out) const
{
int ret = OB_SUCCESS;
ObCastMode cast_mode = CM_NONE;
EXPR_DEFINE_CAST_CTX(expr_ctx, cast_mode);
LOG_DEBUG("ObExprSubstr cast_param_type_for_mysql in.get_type(): ", K(in.get_type()));
// select substr('abcd', '1.9'); MySQL truncate'1.9' to 1
// select substr('abcd', 1.9), MySQL round 1.9 to 2
// select substr('abcd', '1.9')中,MySQL对'1.9'进行trunc操作
// select substr('abcd', 1.9)中,MySQL对1.9进行round操作
if (ObVarcharType == in.get_type()) {
int64_t tmp = 0;
if (OB_FAIL(ObExprUtil::get_trunc_int64(in, expr_ctx, tmp))) {
@ -205,8 +288,10 @@ int ObExprSubstr::cast_param_type_for_mysql(const ObObj& in, ObExprCtx& expr_ctx
return ret;
}
int ObExprSubstr::calc_result2_for_mysql(
ObObj& result, const ObObj& text, const ObObj& start_pos, ObExprCtx& expr_ctx) const
int ObExprSubstr::calc_result2_for_mysql(ObObj &result,
const ObObj &text,
const ObObj &start_pos,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
ObObj trunced_start_pos;
@ -220,8 +305,10 @@ int ObExprSubstr::calc_result2_for_mysql(
return ret;
}
int ObExprSubstr::calc_result2_for_oracle(
ObObj& result, const ObObj& text, const ObObj& start_pos, ObExprCtx& expr_ctx) const
int ObExprSubstr::calc_result2_for_oracle(ObObj &result,
const ObObj &text,
const ObObj &start_pos,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
bool is_clob = text.is_clob() ? true : false;
@ -233,13 +320,12 @@ int ObExprSubstr::calc_result2_for_oracle(
result.set_null();
} else {
TYPE_CHECK(start_pos, ObNumberType);
const ObString& str_val = text.get_varchar();
const ObString &str_val = text.get_varchar();
int64_t start_pos_val = 0;
LOG_DEBUG("ObExprSubstr", K(ret), K(str_val), K(start_pos));
if (OB_FAIL(ObExprUtil::get_trunc_int64(start_pos, expr_ctx, start_pos_val))) {
LOG_WARN("get int value failed", K(ret));
} else if (OB_FAIL(calc(
result, str_val, start_pos_val, text.get_string().length() - start_pos_val + 1, cs_type, is_clob))) {
} else if (OB_FAIL(calc(result, str_val, start_pos_val, text.get_string().length() - start_pos_val + 1, cs_type, is_clob))) {
LOG_WARN("failed to calc for substr", K(str_val), K(start_pos), K(ret));
} else {
if (!result.is_null()) {
@ -250,19 +336,11 @@ int ObExprSubstr::calc_result2_for_oracle(
return ret;
}
int ObExprSubstr::calc_result2(ObObj& result, const ObObj& text, const ObObj& start_pos, ObExprCtx& expr_ctx) const
{
int ret = OB_SUCCESS;
if (share::is_oracle_mode()) {
ret = calc_result2_for_oracle(result, text, start_pos, expr_ctx);
} else {
ret = calc_result2_for_mysql(result, text, start_pos, expr_ctx);
}
return ret;
}
int ObExprSubstr::calc_result3_for_mysql(
ObObj& result, const ObObj& text, const ObObj& start_pos, const ObObj& length, ObExprCtx& expr_ctx) const
int ObExprSubstr::calc_result3_for_mysql(ObObj &result,
const ObObj &text,
const ObObj &start_pos,
const ObObj &length,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
ObObj trunced_start_pos;
@ -276,17 +354,18 @@ int ObExprSubstr::calc_result3_for_mysql(
} else {
if (OB_FAIL(cast_param_type_for_mysql(start_pos, expr_ctx, trunced_start_pos))) {
LOG_WARN("ObExprSubstr cast_param_type_for_mysql failed", K(start_pos.get_type()));
} else if (OB_FAIL(cast_param_type_for_mysql(length, expr_ctx, trunced_length))) {
} else if (OB_FAIL(cast_param_type_for_mysql(length, expr_ctx, trunced_length))){
LOG_WARN("ObExprSubstr cast_param_type_for_mysql failed", K(length.get_type()));
} else {
TYPE_CHECK(text, ObVarcharType);
// text param can be varchar or any type in text tc
TYPE_CHECK(trunced_start_pos, ObIntType);
TYPE_CHECK(trunced_length, ObIntType);
const ObString& str_val = text.get_varchar();
const ObString &str_val = text.get_varchar();
int64_t start_pos_val = trunced_start_pos.get_int();
int64_t length_val = trunced_length.get_int();
if (OB_FAIL(calc(result, str_val, start_pos_val, length_val, cs_type, false))) {
LOG_WARN("failed to calc for substr", K(text), K(trunced_start_pos), K(trunced_length), K(ret));
LOG_WARN("failed to calc for substr", K(text), K(trunced_start_pos),
K(trunced_length), K(ret));
} else {
if (!result.is_null()) {
result.set_collation(result_type_);
@ -297,8 +376,11 @@ int ObExprSubstr::calc_result3_for_mysql(
return ret;
}
int ObExprSubstr::calc_result3_for_oracle(
ObObj& result, const ObObj& text, const ObObj& start_pos, const ObObj& length, ObExprCtx& expr_ctx) const
int ObExprSubstr::calc_result3_for_oracle(ObObj &result,
const ObObj &text,
const ObObj &start_pos,
const ObObj &length,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
bool is_clob = text.is_clob() ? true : false;
@ -312,72 +394,87 @@ int ObExprSubstr::calc_result3_for_oracle(
} else {
TYPE_CHECK(start_pos, ObNumberType);
TYPE_CHECK(length, ObNumberType);
const ObString& str_val = text.get_varchar();
const ObString &str_val = text.get_varchar();
int64_t start_pos_val = 0;
int64_t length_val = 0;
LOG_DEBUG("ObExprSubstr", K(share::is_oracle_mode()), K(ret), K(str_val), K(start_pos), K(length));
if (OB_FAIL(ObExprUtil::get_trunc_int64(start_pos, expr_ctx, start_pos_val)) ||
ObExprUtil::get_trunc_int64(length, expr_ctx, length_val)) {
LOG_DEBUG("ObExprSubstr", K(lib::is_oracle_mode()), K(ret), K(str_val), K(start_pos), K(length));
if (OB_FAIL(ObExprUtil::get_trunc_int64(start_pos, expr_ctx, start_pos_val))
|| ObExprUtil::get_trunc_int64(length, expr_ctx, length_val)) {
LOG_WARN("get int value failed", K(ret), K(start_pos), K(length));
} else if (OB_FAIL(calc(result, str_val, start_pos_val, length_val, cs_type, is_clob))) {
LOG_WARN("failed to calc for substr", K(text), K(start_pos), K(length), K(ret));
} else {
if (!result.is_null()) {
result.set_collation(result_type_);
result.set_meta_type(result_type_);
}
}
}
return ret;
}
int ObExprSubstr::calc_result3(
ObObj& result, const ObObj& text, const ObObj& start_pos, const ObObj& length, ObExprCtx& expr_ctx) const
{
int ret = OB_SUCCESS;
if (share::is_oracle_mode()) {
ret = calc_result3_for_oracle(result, text, start_pos, length, expr_ctx);
} else {
ret = calc_result3_for_mysql(result, text, start_pos, length, expr_ctx);
}
return ret;
}
int ObExprSubstr::substr(common::ObString& varchar, const common::ObString& text, const int64_t start_pos,
const int64_t length, common::ObCollationType cs_type)
int ObExprSubstr::substr(common::ObString &varchar,
const common::ObString &text,
const int64_t start_pos,
const int64_t length,
common::ObCollationType cs_type,
const bool do_ascii_optimize_check)
{
int ret = OB_SUCCESS;
varchar = text;
if (OB_UNLIKELY(0 >= varchar.length() || 0 >= length)) {
// empty result string
varchar.assign(NULL, 0);
} else {
int64_t start = start_pos;
int64_t res_len = 0;
int64_t mb_len = ObCharset::strlen_char(cs_type, varchar.ptr(), varchar.length());
if (share::is_oracle_mode() && 0 == start) {
bool is_ascii = false;
if (lib::is_oracle_mode() && 0 == start_pos) {
start = 1;
}
start = (start >= 0) ? start - 1 : start + mb_len;
if (OB_UNLIKELY(start < 0 || start >= mb_len)) {
start = (start >= 0) ? start - 1 : start + varchar.length();
if (OB_UNLIKELY(start < 0 || start >= varchar.length())) {
varchar.assign(NULL, 0);
} else {
// It holds that 0<=start<mb_len && length > 0
res_len = min(length, mb_len - start);
int64_t offset = ObCharset::charpos(cs_type, varchar.ptr(), varchar.length(), start);
res_len = ObCharset::charpos(
cs_type, varchar.ptr() + offset, (offset == 0) ? varchar.length() : varchar.length() - offset + 1, res_len);
varchar.assign_ptr(varchar.ptr() + offset, static_cast<int32_t>(res_len));
if (do_ascii_optimize_check) { // ObCharsetType is CHARSET_UTF8MB4 or CHARSET_GBK
res_len = min(length, varchar.length() - start);
is_ascii = storage::is_ascii_str(varchar.ptr(), start + res_len);
}
if (is_ascii) {
varchar.assign_ptr(varchar.ptr() + start, static_cast<int32_t>(res_len));
} else { // If not all the front chars in param is ascii, rollback to original method.
start = start_pos;
res_len = 0;
int64_t mb_len = ObCharset::strlen_char(cs_type, varchar.ptr(), varchar.length());
if (lib::is_oracle_mode() && 0 == start_pos) {
start = 1;
}
start = (start >= 0) ? start - 1 : start + mb_len;
if (OB_UNLIKELY(start < 0 || start >= mb_len)) {
varchar.assign(NULL, 0);
} else {
//It holds that 0<=start<mb_len && length > 0
res_len = min(length, mb_len - start);
int64_t offset = ObCharset::charpos(cs_type, varchar.ptr(), varchar.length(), start);
res_len = ObCharset::charpos(cs_type, varchar.ptr() + offset,
(offset == 0) ? varchar.length() : varchar.length() - offset + 1, res_len);
varchar.assign_ptr(varchar.ptr() + offset, static_cast<int32_t>(res_len));
}
}
}
}
return ret;
}
int ObExprSubstr::calc(ObObj& result, const ObString& text, const int64_t start_pos, const int64_t length,
ObCollationType cs_type, const bool is_clob)
int ObExprSubstr::calc(ObObj &result,
const ObString &text,
const int64_t start_pos,
const int64_t length,
ObCollationType cs_type,
const bool is_clob)
{
int ret = OB_SUCCESS;
ObString varchar;
if (OB_FAIL(substr(varchar, text, start_pos, length, cs_type))) {
if (OB_FAIL(substr(varchar, text, start_pos, length, cs_type, storage::can_do_ascii_optimize(cs_type)))) {
LOG_WARN("get substr failed", K(ret));
} else {
if (varchar.length() <= 0 && lib::is_oracle_mode() && !is_clob) {
@ -393,21 +490,9 @@ int ObExprSubstr::calc(ObObj& result, const ObString& text, const int64_t start_
return ret;
}
int ObExprSubstr::calc_resultN(ObObj& result, const ObObj* objs_array, int64_t param_num, ObExprCtx& expr_ctx) const
{
int ret = OB_SUCCESS;
if (2 == param_num) {
ret = calc_result2(result, objs_array[0], objs_array[1], expr_ctx);
} else if (3 == param_num) {
ret = calc_result3(result, objs_array[0], objs_array[1], objs_array[2], expr_ctx);
} else {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument number for substr()", K(param_num), K(ret));
}
return ret;
}
int ObExprSubstr::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const
int ObExprSubstr::cg_expr(ObExprCGCtx &op_cg_ctx,
const ObRawExpr &raw_expr,
ObExpr &rt_expr) const
{
int ret = OB_SUCCESS;
UNUSED(op_cg_ctx);
@ -415,31 +500,42 @@ int ObExprSubstr::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObE
CK(2 == rt_expr.arg_cnt_ || 3 == rt_expr.arg_cnt_);
if (OB_SUCC(ret)) {
rt_expr.eval_func_ = eval_substr;
if (2 == rt_expr.arg_cnt_
&& rt_expr.args_[0]->is_batch_result()
&& !rt_expr.args_[1]->is_batch_result()) {
rt_expr.eval_batch_func_ = eval_substr_batch;
} else if (3 == rt_expr.arg_cnt_
&& rt_expr.args_[0]->is_batch_result()
&& !rt_expr.args_[1]->is_batch_result()
&& !rt_expr.args_[2]->is_batch_result()) {
rt_expr.eval_batch_func_ = eval_substr_batch;
}
}
return ret;
}
int ObExprSubstr::eval_substr(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum)
int ObExprSubstr::eval_substr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
if (OB_FAIL(expr.eval_param_value(ctx))) {
LOG_WARN("evaluate parameters failed", K(ret));
} else {
ObDatum* str_datum = &expr.locate_param_datum(ctx, 0);
ObDatum* pos_datum = &expr.locate_param_datum(ctx, 1);
ObDatum* len_datum = NULL;
ObDatum *str_datum = &expr.locate_param_datum(ctx, 0);
ObDatum *pos_datum = &expr.locate_param_datum(ctx, 1);
ObDatum *len_datum = NULL;
if (expr.arg_cnt_ > 2) {
len_datum = &expr.locate_param_datum(ctx, 2);
}
if (str_datum->is_null() || pos_datum->is_null() || (NULL != len_datum && len_datum->is_null())) {
if (str_datum->is_null() || pos_datum->is_null()
|| (NULL != len_datum && len_datum->is_null())) {
expr_datum.set_null();
} else {
ObString input = str_datum->get_string();
int64_t pos = 0;
int64_t len = input.length();
if (lib::is_oracle_mode()) {
if (OB_FAIL(ObExprUtil::trunc_num2int64(*pos_datum, pos)) ||
(NULL != len_datum && OB_FAIL(ObExprUtil::trunc_num2int64(*len_datum, len)))) {
if (OB_FAIL(ObExprUtil::trunc_num2int64(*pos_datum, pos))
|| (NULL != len_datum && OB_FAIL(ObExprUtil::trunc_num2int64(*len_datum, len)))) {
LOG_WARN("get integer value failed", K(ret));
}
} else {
@ -448,10 +544,13 @@ int ObExprSubstr::eval_substr(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_
}
ObString output;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(substr(output, input, pos, len, expr.datum_meta_.cs_type_))) {
} else if (OB_FAIL(substr(output, input, pos, len,
expr.datum_meta_.cs_type_,
storage::can_do_ascii_optimize(expr.datum_meta_.cs_type_)))) {
LOG_WARN("get substr failed", K(ret));
} else {
if (OB_UNLIKELY(output.length() <= 0) && lib::is_oracle_mode() && !expr.args_[0]->datum_meta_.is_clob()) {
if (OB_UNLIKELY(output.length() <= 0)
&& lib::is_oracle_mode() && !expr.args_[0]->datum_meta_.is_clob()) {
expr_datum.set_null();
} else {
expr_datum.set_string(output);
@ -462,5 +561,99 @@ int ObExprSubstr::eval_substr(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_
return ret;
}
} // namespace sql
} // namespace oceanbase
int ObExprSubstr::eval_substr_batch(const ObExpr &expr, ObEvalCtx &ctx,
const ObBitVector &skip, const int64_t batch_size)
{
LOG_DEBUG("eval substr in batch mode", K(batch_size));
int ret = OB_SUCCESS;
ObDatum *results = expr.locate_batch_datums(ctx);
if (OB_ISNULL(results)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr results frame is not init", K(ret));
} else {
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
const bool has_len_param = expr.arg_cnt_ > 2 ? true : false;
if (OB_FAIL(expr.args_[0]->eval_batch(ctx, skip, batch_size))) {
LOG_WARN("failed to eval batch result args0", K(ret));
} else {
ObDatum *datum_array = expr.args_[0]->locate_batch_datums(ctx);
ObString output;
ObString input;
ObDatum *pos_datum = NULL;
ObDatum *len_datum = NULL;
int64_t pos = 0;
int64_t len = INT_MAX64;
bool is_text_params_all_null = true; // used for mark if all the first params are all null
bool is_result_all_null = false;
for (int64_t j = 0; is_text_params_all_null && j < batch_size; ++j) {
if (skip.at(j) || eval_flags.at(j)) {
continue;
} else if (!datum_array[j].is_null()) {
is_text_params_all_null = false;
}
}
if (is_text_params_all_null) {
is_result_all_null = true;
} else if (OB_FAIL(expr.args_[1]->eval(ctx, pos_datum))) {
LOG_WARN("eval pos_datum failed", K(ret));
} else if (pos_datum->is_null()) {
is_result_all_null = true;
} else if (has_len_param && OB_FAIL(expr.args_[2]->eval(ctx, len_datum))) {
LOG_WARN("eval len_datum failed", K(ret));
} else if (has_len_param && len_datum->is_null()) {
is_result_all_null = true;
}
if (OB_FAIL(ret)) {
} else if (is_result_all_null) { // any param is null, result is null
for (int64_t j = 0; OB_SUCC(ret) && j < batch_size; ++j) {
if (skip.at(j) || eval_flags.at(j)) {
continue;
} else {
results[j].set_null();
eval_flags.set(j);
}
}
} else {
if (is_oracle_mode()) {
if (OB_FAIL(ObExprUtil::trunc_num2int64(*pos_datum, pos))
|| (NULL != len_datum && OB_FAIL(ObExprUtil::trunc_num2int64(*len_datum, len)))) {
LOG_WARN("get integer value failed", K(ret));
}
} else {
pos = pos_datum->get_int();
len = has_len_param ? len_datum->get_int() : len;
}
bool do_ascii_optimize_check = storage::can_do_ascii_optimize(expr.datum_meta_.cs_type_);
for (int64_t j = 0; OB_SUCC(ret) && (j < batch_size); ++j) {
if (skip.at(j) || eval_flags.at(j)) {
continue;
} else if (datum_array[j].is_null()) {
results[j].set_null();
eval_flags.set(j);
} else if (OB_FAIL(substr(
output,
datum_array[j].get_string(),
pos,
min(len, datum_array[j].get_string().length()),
expr.datum_meta_.cs_type_, do_ascii_optimize_check))) {
LOG_WARN("get substr failed", K(ret));
} else {
if (OB_UNLIKELY(output.length() <= 0)
&& lib::is_oracle_mode() && !expr.args_[0]->datum_meta_.is_clob()) {
results[j].set_null();
} else {
results[j].set_string(output);
}
eval_flags.set(j);
}
}
}
}
}
return ret;
}
} /* sql */
} /* oceanbase */