diff --git a/src/sql/engine/expr/ob_expr_lrpad.cpp b/src/sql/engine/expr/ob_expr_lrpad.cpp index 283bde2bef..bd8d9f7076 100644 --- a/src/sql/engine/expr/ob_expr_lrpad.cpp +++ b/src/sql/engine/expr/ob_expr_lrpad.cpp @@ -198,11 +198,35 @@ int ObExprBaseLRpad::calc_type_length_oracle(const ObExprResType &result_type, return ret; } +int ObExprBaseLRpad::get_origin_len_obj(ObObj &len_obj) const +{ + int ret = OB_SUCCESS; + ObRawExpr *expr = NULL; + if (OB_ISNULL(expr = get_raw_expr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get_raw_expr", K(ret)); + } else if (expr->get_children_count() >= 2 && OB_NOT_NULL(expr = expr->get_param_expr(1)) + && expr->get_expr_type() == T_FUN_SYS_CAST && CM_IS_IMPLICIT_CAST(expr->get_extra())) { + do { + if (expr->get_children_count() >= 1 + && OB_ISNULL(expr = expr->get_param_expr(0))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get_param_expr", K(ret)); + } + } while (OB_SUCC(ret) && T_FUN_SYS_CAST == expr->get_expr_type() + && CM_IS_IMPLICIT_CAST(expr->get_extra())); + if (OB_SUCC(ret)) { + len_obj = expr->get_result_type().get_param(); + } + } + return ret; +} + int ObExprBaseLRpad::calc_type(ObExprResType &type, ObExprResType &text, ObExprResType &len, ObExprResType *pad_text, - ObExprTypeCtx &type_ctx) + ObExprTypeCtx &type_ctx) const { int ret = OB_SUCCESS; ObObjType text_type = ObNullType; @@ -248,9 +272,6 @@ int ObExprBaseLRpad::calc_type(ObExprResType &type, len.set_calc_type(len_type); if (is_mysql_mode()) { pad_obj = pad_text->get_param(); - type.set_type(text_type); - text.set_calc_type(text_type); - pad_text->set_calc_type(text_type); ObSEArray types; OZ(types.push_back(text)); OZ(types.push_back(*pad_text)); @@ -258,6 +279,28 @@ int ObExprBaseLRpad::calc_type(ObExprResType &type, type_ctx.get_coll_type())); OX(text.set_calc_collation_type(type.get_collation_type())); OX(pad_text->set_calc_collation_type(type.get_collation_type())); + if (OB_SUCC(ret)) { + // len expr may add cast, search real len obj + if (OB_FAIL(get_origin_len_obj(length_obj))) { + LOG_WARN("fail to get ori len obj", K(ret)); + } else if (!length_obj.is_null()) { + if (OB_FAIL(calc_type_length_mysql(type, text_obj, pad_obj, length_obj, type_ctx.get_session(), text_len))) { + LOG_WARN("failed to calc result type length mysql mode", K(ret)); + } + } else { + text_len = max_len; + } + if (OB_SUCC(ret)) { + text_type = get_result_type_mysql(text_len); + type.set_type(text_type); + if (!ob_is_text_tc(text.get_type())) { + text.set_calc_type(text_type); + } + if (!ob_is_text_tc(pad_text->get_type())) { + pad_text->set_calc_type(text_type); + } + } + } } else { ObSEArray types; OZ(types.push_back(&text)); @@ -287,8 +330,6 @@ int ObExprBaseLRpad::calc_type(ObExprResType &type, if (!length_obj.is_null()) { if (is_oracle_mode && OB_FAIL(calc_type_length_oracle(type, text_obj, pad_obj, length_obj, text_len))) { LOG_WARN("failed to calc result type length oracle mode", K(ret)); - } else if (!is_oracle_mode && OB_FAIL(calc_type_length_mysql(type, text_obj, pad_obj, length_obj, type_ctx.get_session(), text_len))) { - LOG_WARN("failed to calc result type length mysql mode", K(ret)); } } else { text_len = max_len; @@ -640,6 +681,7 @@ int ObExprBaseLRpad::calc_mysql_inner(const LRpadType pad_type, const ObCollationType cs_type = expr.datum_meta_.cs_type_; const ObObjType type = expr.datum_meta_.type_; bool has_lob_header = expr.obj_meta_.has_lob_header(); + bool has_set_to_lob_locator = false; int64_t int_len = len.get_int(); if (int_len < 0) { res.set_null(); @@ -652,28 +694,46 @@ int ObExprBaseLRpad::calc_mysql_inner(const LRpadType pad_type, // only substr needed result_size = ObCharset::charpos(cs_type, str_text.ptr(), str_text.length(), int_len); res.set_string(ObString(result_size, str_text.ptr())); - } else if (str_pad.length() == 0) { - res.set_string(ObString::make_empty_string()); - } else if (OB_FAIL(get_padding_info_mysql(cs_type, str_text, int_len, str_pad, - max_result_size, repeat_count, prefix_size, result_size))) { - LOG_WARN("Failed to get padding info", K(ret), K(str_text), K(int_len), - K(str_pad), K(max_result_size)); - } else if (result_size > max_result_size) { - res.set_null(); - if (pad_type == RPAD_TYPE) { - LOG_USER_WARN(OB_ERR_FUNC_RESULT_TOO_LARGE, "rpad", static_cast(max_result_size)); - } else { - LOG_USER_WARN(OB_ERR_FUNC_RESULT_TOO_LARGE, "lpad", static_cast(max_result_size)); - } - } else if (OB_FAIL(padding(pad_type, cs_type, str_text.ptr(), str_text.length(), str_pad.ptr(), - str_pad.length(), prefix_size, repeat_count, false, &res_alloc, - result_ptr, result_size, type, has_lob_header))) { - LOG_WARN("Failed to pad", K(ret), K(str_text), K(str_pad), K(prefix_size), K(repeat_count)); } else { - if (NULL == result_ptr || 0 == result_size) { + has_set_to_lob_locator = true; + if (str_pad.length() == 0) { + res.set_string(ObString::make_empty_string()); + } else if (OB_FAIL(get_padding_info_mysql(cs_type, str_text, int_len, str_pad, + max_result_size, repeat_count, prefix_size, result_size))) { + LOG_WARN("Failed to get padding info", K(ret), K(str_text), K(int_len), + K(str_pad), K(max_result_size)); + } else if (result_size > max_result_size) { res.set_null(); + if (pad_type == RPAD_TYPE) { + LOG_USER_WARN(OB_ERR_FUNC_RESULT_TOO_LARGE, "rpad", static_cast(max_result_size)); + } else { + LOG_USER_WARN(OB_ERR_FUNC_RESULT_TOO_LARGE, "lpad", static_cast(max_result_size)); + } + } else if (OB_FAIL(padding(pad_type, cs_type, str_text.ptr(), str_text.length(), str_pad.ptr(), + str_pad.length(), prefix_size, repeat_count, false, &res_alloc, + result_ptr, result_size, type, has_lob_header))) { + LOG_WARN("Failed to pad", K(ret), K(str_text), K(str_pad), K(prefix_size), K(repeat_count)); } else { - res.set_string(result_ptr, result_size); + if (NULL == result_ptr || 0 == result_size) { + res.set_null(); + } else { + res.set_string(result_ptr, result_size); + } + } + } + if (OB_SUCC(ret) && ob_is_text_tc(type) && !res.is_null() && + has_lob_header && !has_set_to_lob_locator) { + ObString data = res.get_string(); + ObTextStringResult result_buffer(type, has_lob_header, &res_alloc); + int64_t buffer_len = 0; + if (OB_FAIL(result_buffer.init(data.length()))) { + LOG_WARN("init stringtextbuffer failed", K(ret), K(data)); + } else if (OB_FAIL(result_buffer.append(data))) { + LOG_WARN("temp lob lseek failed", K(ret)); + } else { + ObString output; + result_buffer.get_result_buffer(output); + res.set_string(output); } } return ret; diff --git a/src/sql/engine/expr/ob_expr_lrpad.h b/src/sql/engine/expr/ob_expr_lrpad.h index df8bb27541..11ebe229e3 100644 --- a/src/sql/engine/expr/ob_expr_lrpad.h +++ b/src/sql/engine/expr/ob_expr_lrpad.h @@ -30,11 +30,11 @@ public: virtual ~ObExprBaseLRpad(); - static int calc_type(ObExprResType &type, - ObExprResType &text, - ObExprResType &len, - ObExprResType *pad_text, - common::ObExprTypeCtx &type_ctx); + int calc_type(ObExprResType &type, + ObExprResType &text, + ObExprResType &len, + ObExprResType *pad_text, + common::ObExprTypeCtx &type_ctx) const; static int padding(LRpadType type, const common::ObCollationType coll_type, @@ -136,6 +136,7 @@ public: static int calc_oracle(LRpadType pad_type, const ObExpr &expr, const common::ObDatum &text, const common::ObDatum &len, const common::ObDatum &pad_text, common::ObIAllocator &res_alloc, ObDatum &res, bool &is_unchanged_clob); + int get_origin_len_obj(ObObj &len_obj) const; private: DISALLOW_COPY_AND_ASSIGN(ObExprBaseLRpad); }; diff --git a/src/sql/engine/expr/ob_expr_repeat.cpp b/src/sql/engine/expr/ob_expr_repeat.cpp index 9a2bd382f8..8b068abf43 100644 --- a/src/sql/engine/expr/ob_expr_repeat.cpp +++ b/src/sql/engine/expr/ob_expr_repeat.cpp @@ -46,7 +46,9 @@ int ObExprRepeat::calc_result_type2(ObExprResType &type, ObExprTypeCtx &type_ctx) const { int ret = OB_SUCCESS; - text.set_calc_type(common::ObVarcharType); + if (!text.is_string_type()) { + text.set_calc_type(common::ObVarcharType); + } count.set_calc_type(common::ObIntType); // Set cast mode for %count parameter, truncate string to integer. type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_STRING_INTEGER_TRUNC); diff --git a/src/sql/engine/expr/ob_expr_space.cpp b/src/sql/engine/expr/ob_expr_space.cpp index 3686b30a2f..3c0de8351f 100644 --- a/src/sql/engine/expr/ob_expr_space.cpp +++ b/src/sql/engine/expr/ob_expr_space.cpp @@ -26,7 +26,7 @@ namespace sql { using namespace common; ObExprSpace::ObExprSpace(ObIAllocator &alloc) - : ObFuncExprOperator(alloc, T_FUN_SYS_SPACE, N_SPACE, 1, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) {} + : ObStringExprOperator(alloc, T_FUN_SYS_SPACE, N_SPACE, 1, VALID_FOR_GENERATED_COL) {} inline int ObExprSpace::calc_result_type1( ObExprResType &type, @@ -36,11 +36,41 @@ inline int ObExprSpace::calc_result_type1( int ret = OB_SUCCESS; // space is mysql only expr CK(lib::is_mysql_mode()); - - type.set_type(ObVarcharType); + ObObjType res_type = ObMaxType; + if (type1.is_null()) { + res_type = ObVarcharType; + } else if (type1.is_literal()) { + const ObObj &obj = type1.get_param(); + ObArenaAllocator alloc(ObModIds::OB_SQL_RES_TYPE); + const ObDataTypeCastParams dtc_params = + ObBasicSessionInfo::create_dtc_params(type_ctx.get_session()); + int64_t cur_time = 0; + ObCastMode cast_mode = CM_NONE; + if (OB_FAIL(ObSQLUtils::get_default_cast_mode(type_ctx.get_session(), cast_mode))) { + LOG_WARN("failed to get default cast mode", K(ret)); + } else { + cast_mode |= CM_WARN_ON_FAIL; + ObCastCtx cast_ctx( + &alloc, &dtc_params, cur_time, cast_mode, CS_TYPE_INVALID); + int64_t count_val = 0; + EXPR_GET_INT64_V2(obj, count_val); + res_type = get_result_type_mysql(count_val); + } + } else { + res_type = ObLongTextType; + } + type.set_type(res_type); type.set_collation_level(type1.get_collation_level()); type.set_collation_type(get_default_collation_type(type.get_type(), *type_ctx.get_session())); - type.set_length(OB_MAX_VARCHAR_LENGTH); + if (ObVarcharType == type.get_type()) { + type.set_length(MAX_CHAR_LENGTH_FOR_VARCAHR_RESULT); + } else if (ob_is_text_tc(type.get_type())) { + const int32_t mbmaxlen = 4; + const int32_t default_text_length = + ObAccuracy::DDL_DEFAULT_ACCURACY[type.get_type()].get_length() / mbmaxlen; + // need to set a correct length for text tc in mysql mode + type.set_length(default_text_length); + } type1.set_calc_type(ObIntType); // Set cast mode for parameter casting, truncate string to integer. type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_STRING_INTEGER_TRUNC); diff --git a/src/sql/engine/expr/ob_expr_space.h b/src/sql/engine/expr/ob_expr_space.h index c7caf448e5..1dd25d0f3b 100644 --- a/src/sql/engine/expr/ob_expr_space.h +++ b/src/sql/engine/expr/ob_expr_space.h @@ -18,7 +18,7 @@ namespace oceanbase { namespace sql { -class ObExprSpace : public ObFuncExprOperator +class ObExprSpace : public ObStringExprOperator { public: diff --git a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_repeat.result b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_repeat.result index 599bcd63fb..6d956c5ab0 100644 --- a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_repeat.result +++ b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_repeat.result @@ -82,3 +82,17 @@ select repeat(1.414, 2); select repeat("abc", 200000000); ERROR HY000: Result of repeat() was larger than max_allowed_packet (4194304) - truncated +drop table t2; +create table t2 as select repeat('a', 512),repeat('a', 513),repeat('a',32767),repeat('a',32768),repeat('a',65535),repeat('a',65536) from dual; +desc t2; ++-------------------+--------------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------------------+--------------+------+-----+---------+-------+ +| repeat('a', 512) | varchar(512) | YES | | NULL | | +| repeat('a', 513) | text | YES | | NULL | | +| repeat('a',32767) | text | YES | | NULL | | +| repeat('a',32768) | text | YES | | NULL | | +| repeat('a',65535) | text | YES | | NULL | | +| repeat('a',65536) | longtext | YES | | NULL | | ++-------------------+--------------+------+-----+---------+-------+ +drop table t2; diff --git a/tools/deploy/mysql_test/test_suite/static_engine/t/expr_repeat.test b/tools/deploy/mysql_test/test_suite/static_engine/t/expr_repeat.test index 7d7d04bb16..1bc0c7fefe 100644 --- a/tools/deploy/mysql_test/test_suite/static_engine/t/expr_repeat.test +++ b/tools/deploy/mysql_test/test_suite/static_engine/t/expr_repeat.test @@ -33,6 +33,12 @@ select repeat(1.414, 2); --error 1301 select repeat("abc", 200000000); +--error 0,1051 +drop table t2; +create table t2 as select repeat('a', 512),repeat('a', 513),repeat('a',32767),repeat('a',32768),repeat('a',65535),repeat('a',65536) from dual; +desc t2; +drop table t2; + --enable_warnings connection syscon;