diff --git a/src/sql/engine/expr/ob_expr_like.cpp b/src/sql/engine/expr/ob_expr_like.cpp index 7e04f49b90..e578e5166b 100644 --- a/src/sql/engine/expr/ob_expr_like.cpp +++ b/src/sql/engine/expr/ob_expr_like.cpp @@ -208,16 +208,15 @@ int ObExprLike::check_pattern_valid(const T &pattern, } else if (pre_char_is_escape) { // If pre char is escape char, then the following char must be '_' or '%' // Eg: select 1 from t1 where 'a' like 'a_a%' escape 'a'; -- it's ok - if (1 != char_len) { - ret = OB_ERR_INVALID_CHAR_FOLLOWING_ESCAPE_CHAR; - LOG_WARN("missing or illegal character following the escape character", - K(escape_val), K(pattern_val), K(ret)); - } else if ('%' == *buf_start || '_' == *buf_start) { + ObString percent_str = ObCharsetUtils::get_const_str(coll_type, '%'); + ObString underline_str = ObCharsetUtils::get_const_str(coll_type, '_'); + const ObString pattern_char = ObString(char_len, buf_start); + if (0 == pattern_char.compare(percent_str) || 0 == pattern_char.compare(underline_str)) { // it's ok } else { ret = OB_ERR_INVALID_CHAR_FOLLOWING_ESCAPE_CHAR; LOG_WARN("missing or illegal character following the escape character", - K(escape_val), K(pattern_val), K(ret)); + K(escape_val), K(pattern_val), K(pattern_char), K(ret)); } pre_char_is_escape = false; } @@ -361,6 +360,7 @@ int ObExprLike::set_instr_info(ObIAllocator *exec_allocator, //when there are "_" or escape in pattern //the case can not be optimized. use_instr_mode = false; + // since cs_type is CS_TYPE_UTF8MB4_BIN, length of '%' must be 1. } else if ((1 == char_len && '%' == *buf_start)) { //percent sign percent_sign_exist = true; if (OB_LIKELY(instr_len > 0)) { @@ -822,12 +822,16 @@ struct ObNonInstrModeMatcher inline int64_t operator() (const ObCollationType coll_type, const ObString &text_val, const ObString &pattern_val, - int32_t escape_wc) + int32_t escape_wc, + int &ret) { int64_t res = 0; if (OB_UNLIKELY(text_val.length() <= 0 && pattern_val.length() <= 0)) { // empty string res = 1; + } else if (OB_UNLIKELY(CS_TYPE_UTF8MB4_BIN != coll_type && escape_wc == static_cast('%'))) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "escape %"); } else { bool b = ObCharset::wildcmp(coll_type, text_val, pattern_val, escape_wc, static_cast('_'), static_cast('%')); @@ -867,7 +871,7 @@ int ObExprLike::match_text_batch(BATCH_EVAL_FUNC_ARG_DECL, res_datums[i].set_int(res); } else { res_datums[i].set_int(ObNonInstrModeMatcher()(coll_type, text_datums[i].get_string(), - pattern_val, escape_wc)); + pattern_val, escape_wc, ret)); } } else { // text tc ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); @@ -886,7 +890,7 @@ int ObExprLike::match_text_batch(BATCH_EVAL_FUNC_ARG_DECL, res_datums[i].set_int(res); } else { res_datums[i].set_int(ObNonInstrModeMatcher()(coll_type, text_val, - pattern_val, escape_wc)); + pattern_val, escape_wc, ret)); } } } @@ -909,7 +913,7 @@ int ObExprLike::match_text_batch(BATCH_EVAL_FUNC_ARG_DECL, res_datums[i].set_int(res); } else { res_datums[i].set_int(ObNonInstrModeMatcher()(coll_type, text_datums[i].get_string(), - pattern_val, escape_wc)); + pattern_val, escape_wc, ret)); } } else { // text tc ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); @@ -929,7 +933,7 @@ int ObExprLike::match_text_batch(BATCH_EVAL_FUNC_ARG_DECL, res_datums[i].set_int(res); } else { res_datums[i].set_int(ObNonInstrModeMatcher()(coll_type, text_val, - pattern_val, escape_wc)); + pattern_val, escape_wc, ret)); } } } diff --git a/src/sql/engine/expr/ob_expr_like.h b/src/sql/engine/expr/ob_expr_like.h index 385e0c3f7b..62d4eb49c1 100644 --- a/src/sql/engine/expr/ob_expr_like.h +++ b/src/sql/engine/expr/ob_expr_like.h @@ -229,9 +229,15 @@ int ObExprLike::calc_with_non_instr_mode(T &result, } else if (text_val.length() <= 0 && pattern_val.length() <= 0) { // empty string result.set_int(1); + } else if (OB_UNLIKELY(CS_TYPE_UTF8MB4_BIN != coll_type && escape_wc == static_cast('%'))) { + // when cs_type is not utf8mb4_bin and escape = %, there is a bug of wildcmp + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "escape %"); } else { bool b = ObCharset::wildcmp(coll_type, text_val, pattern_val, escape_wc, static_cast('_'), static_cast('%')); + SQL_LOG(DEBUG, "calc_with_non_instr_mode1", K(escape_coll), K(escape_val), K(escape_wc), K(pattern_val), + K(coll_type), KPHEX(text_val.ptr(), text_val.length()), KPHEX(pattern_val.ptr(), pattern_val.length()), K(b)); result.set_int(static_cast(b)); } return ret; diff --git a/src/sql/rewrite/ob_query_range.cpp b/src/sql/rewrite/ob_query_range.cpp index c512f447d7..58a2e22078 100644 --- a/src/sql/rewrite/ob_query_range.cpp +++ b/src/sql/rewrite/ob_query_range.cpp @@ -7506,8 +7506,7 @@ int ObQueryRange::get_like_range(const ObObj &pattern, } else if (OB_ISNULL(escape_str.ptr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Escape str should not be NULL", K(ret)); - } else if (OB_UNLIKELY((lib::is_oracle_mode() && 1 != escape_str.length()) - || (!lib::is_oracle_mode() && 1 > escape_str.length()))) { + } else if (OB_UNLIKELY(1 > escape_str.length())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("failed to check escape length", K(escape_str), K(escape_str.length())); LOG_USER_ERROR(OB_INVALID_ARGUMENT, "ESCAPE");