diff --git a/deps/oblib/src/common/object/ob_obj_funcs.h b/deps/oblib/src/common/object/ob_obj_funcs.h index 90686d756..365aaf224 100644 --- a/deps/oblib/src/common/object/ob_obj_funcs.h +++ b/deps/oblib/src/common/object/ob_obj_funcs.h @@ -952,7 +952,7 @@ inline int obj_print_plain_str( ret = obj_print_sql(obj, buffer, length, pos, params); \ } else if (OB_FAIL(databuff_printf(buffer, length, pos, "'"))) { \ } else if (src_type == dst_type || src_type == CHARSET_INVALID) { \ - ObHexEscapeSqlStr sql_str(obj.get_string()); \ + ObHexEscapeSqlStr sql_str(obj.get_string(), params.skip_escape_); \ pos += sql_str.to_string(buffer + pos, length - pos); \ ret = databuff_printf(buffer, length, pos, "'"); \ } else { \ @@ -965,7 +965,7 @@ inline int obj_print_plain_str( length - pos, \ result_len))) { \ } else { \ - ObHexEscapeSqlStr sql_str(ObString(result_len, buffer + pos)); \ + ObHexEscapeSqlStr sql_str(ObString(result_len, buffer + pos), params.skip_escape_); \ int64_t temp_pos = pos + result_len; \ int64_t data_len = sql_str.to_string(buffer + temp_pos, length - temp_pos); \ if (OB_UNLIKELY(temp_pos + data_len >= length)) { \ @@ -2125,7 +2125,7 @@ inline uint64_t obj_crc64_v3(const ObObj& obj, const uint64_t int ret = OB_SUCCESS; \ if (OB_FAIL(databuff_printf(buffer, length, pos, "n'"))) { \ } else if (src_type == dst_type) { \ - ObHexEscapeSqlStr sql_str(obj.get_string()); \ + ObHexEscapeSqlStr sql_str(obj.get_string(), params.skip_escape_); \ pos += sql_str.to_string(buffer + pos, length - pos); \ ret = databuff_printf(buffer, length, pos, "'"); \ } else { \ @@ -2138,7 +2138,7 @@ inline uint64_t obj_crc64_v3(const ObObj& obj, const uint64_t length - pos, \ result_len))) { \ } else { \ - ObHexEscapeSqlStr sql_str(ObString(result_len, buffer + pos)); \ + ObHexEscapeSqlStr sql_str(ObString(result_len, buffer + pos), params.skip_escape_); \ int64_t temp_pos = pos + result_len; \ int64_t data_len = sql_str.to_string(buffer + temp_pos, length - temp_pos); \ if (OB_UNLIKELY(temp_pos + data_len >= length)) { \ diff --git a/deps/oblib/src/common/object/ob_object.cpp b/deps/oblib/src/common/object/ob_object.cpp index 3ea4e4fa9..c7ef972c1 100644 --- a/deps/oblib/src/common/object/ob_object.cpp +++ b/deps/oblib/src/common/object/ob_object.cpp @@ -1395,6 +1395,11 @@ DEF_TO_STRING(ObHexEscapeSqlStr) buf[buf_pos++] = *cur; } } + } else if (skip_escape_) { + // do not escape_ while in NO_BACKSLASH_ESCAPES mode + for (const char *cur = str_.ptr(); cur < end && buf_pos < buf_len; ++cur) { + buf[buf_pos++] = *cur; + } } else { for (const char* cur = str_.ptr(); cur < end && buf_pos < buf_len; ++cur) { switch (*cur) { diff --git a/deps/oblib/src/common/object/ob_object.h b/deps/oblib/src/common/object/ob_object.h index e6505a266..d4d067ea1 100644 --- a/deps/oblib/src/common/object/ob_object.h +++ b/deps/oblib/src/common/object/ob_object.h @@ -1049,7 +1049,9 @@ struct ObObjPrintParams { struct { uint32_t need_cast_expr_ : 1; uint32_t is_show_create_view_ : 1; - uint32_t reserved_ : 30; + uint32_t use_memcpy_ : 1; + uint32_t skip_escape_ : 1; + uint32_t reserved_ : 28; }; }; }; @@ -4125,7 +4127,9 @@ public: class ObHexEscapeSqlStr { public: - ObHexEscapeSqlStr(const common::ObString& str) : str_(str) + ObHexEscapeSqlStr(const common::ObString &str) : str_(str), skip_escape_(false) + {} + ObHexEscapeSqlStr(const common::ObString &str, const bool skip_escape) : str_(str), skip_escape_(skip_escape) {} ObString str() const { @@ -4136,6 +4140,7 @@ public: private: ObString str_; + bool skip_escape_; }; } // namespace common diff --git a/deps/oblib/src/common/sql_mode/ob_sql_mode.h b/deps/oblib/src/common/sql_mode/ob_sql_mode.h index 91a036821..9431d1551 100644 --- a/deps/oblib/src/common/sql_mode/ob_sql_mode.h +++ b/deps/oblib/src/common/sql_mode/ob_sql_mode.h @@ -42,7 +42,7 @@ extern "C" { #define SMO_MYSQL40 (1ULL << 17) /*not support*/ #define SMO_ANSI (1ULL << 18) #define SMO_NO_AUTO_VALUE_ON_ZERO (1ULL << 19) /* support */ -#define SMO_NO_BACKSLASH_ESCAPES (1ULL << 20) /* not support now */ +#define SMO_NO_BACKSLASH_ESCAPES (1ULL << 20) /* support */ #define SMO_STRICT_TRANS_TABLES (1ULL << 21) /* support */ #define SMO_STRICT_ALL_TABLES (1ULL << 22) /* support */ #define SMO_NO_ZERO_IN_DATE (1ULL << 23) /* deprecated as of MySQL 5.6.17 */ diff --git a/src/sql/engine/dml/ob_table_modify.h b/src/sql/engine/dml/ob_table_modify.h index 72d5c9ad4..8e66c2662 100644 --- a/src/sql/engine/dml/ob_table_modify.h +++ b/src/sql/engine/dml/ob_table_modify.h @@ -405,7 +405,8 @@ protected: rowkey_dist_ctx_(NULL), iter_end_(false), saved_session_(NULL) - {} + { + } virtual ~ObTableModifyCtx() { destroy(); @@ -439,7 +440,14 @@ protected: } const ObObjPrintParams get_obj_print_params() { - return CREATE_OBJ_PRINT_PARAM(exec_ctx_.get_my_session()); + ObObjPrintParams print_params = CREATE_OBJ_PRINT_PARAM(exec_ctx_.get_my_session()); + print_params.need_cast_expr_ = true; + // bugfix:https://work.aone.alibaba-inc.com/issue/36658497 + // in NO_BACKSLASH_ESCAPES, obj_print_sql won't escape. + // We use skip_escape_ to indicate this case. It will finally be passed to ObHexEscapeSqlStr. + GET_SQL_MODE_BIT( + IS_NO_BACKSLASH_ESCAPES, exec_ctx_.get_my_session()->get_sql_mode(), print_params.skip_escape_); + return print_params; } int check_stack(); diff --git a/src/sql/engine/dml/ob_table_modify_op.cpp b/src/sql/engine/dml/ob_table_modify_op.cpp index 1c9fbc986..df5fe96a4 100644 --- a/src/sql/engine/dml/ob_table_modify_op.cpp +++ b/src/sql/engine/dml/ob_table_modify_op.cpp @@ -403,7 +403,8 @@ ObTableModifyOp::ObTableModifyOp(ObExecContext& ctx, const ObOpSpec& spec, ObOpI iter_end_(false), saved_session_(NULL), fk_self_ref_row_res_infos_() -{} +{ +} int ObTableModifyOp::inner_open() { diff --git a/src/sql/engine/dml/ob_table_modify_op.h b/src/sql/engine/dml/ob_table_modify_op.h index b92992e45..011ec5e2a 100644 --- a/src/sql/engine/dml/ob_table_modify_op.h +++ b/src/sql/engine/dml/ob_table_modify_op.h @@ -326,7 +326,13 @@ public: } const ObObjPrintParams get_obj_print_params() { - return CREATE_OBJ_PRINT_PARAM(ctx_.get_my_session()); + ObObjPrintParams print_params = CREATE_OBJ_PRINT_PARAM(ctx_.get_my_session()); + print_params.need_cast_expr_ = true; + // bugfix:https://work.aone.alibaba-inc.com/issue/36658497 + // in NO_BACKSLASH_ESCAPES, obj_print_sql won't escape. + // We use skip_escape_ to indicate this case. It will finally be passed to ObHexEscapeSqlStr. + GET_SQL_MODE_BIT(IS_NO_BACKSLASH_ESCAPES, ctx_.get_my_session()->get_sql_mode(), print_params.skip_escape_); + return print_params; } int init_foreign_key_operation(); int check_rowkey_is_null(const ObExprPtrIArray& row, int64_t rowkey_cnt, bool& is_null) const; diff --git a/src/sql/resolver/cmd/ob_load_data_resolver.cpp b/src/sql/resolver/cmd/ob_load_data_resolver.cpp index c3e177a48..4add28a14 100644 --- a/src/sql/resolver/cmd/ob_load_data_resolver.cpp +++ b/src/sql/resolver/cmd/ob_load_data_resolver.cpp @@ -274,7 +274,13 @@ int ObLoadDataResolver::resolve(const ParseNode& parse_tree) if (OB_SUCC(ret)) { /* 5. opt_field */ ObDataInFileStruct& data_struct_in_file = load_stmt->get_data_struct_in_file(); - const ParseNode* child_node = node->children_[ENUM_OPT_FIELD]; + bool no_default_escape = false; + IS_NO_BACKSLASH_ESCAPES(session_info_->get_sql_mode(), no_default_escape); + if (no_default_escape) { + data_struct_in_file.field_escaped_char_ = INT64_MAX; + data_struct_in_file.field_escaped_str_ = ""; + } + const ParseNode *child_node = node->children_[ENUM_OPT_FIELD]; if (NULL != child_node) { if (T_INTO_FIELD_LIST != child_node->type_) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp index 4038d38ac..0e09980dc 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp @@ -2275,11 +2275,25 @@ int ObRawExprResolverImpl::process_like_node(const ParseNode* node, ObRawExpr*& escape_node.str_value_ = "\\"; escape_node.text_len_ = 0; escape_node.raw_text_ = NULL; + + /* + bugfix:https://work.aone.alibaba-inc.com/issue/36691548 + in NO_BACKSLASH_ESCAPES mode, 'like BINARY xxx' stmt should also set the escapes as null, instead of '\' + */ + bool no_escapes = false; + if (node->children_[1]->type_ == T_FUN_SYS && node->children_[1]->num_child_ == 2 && + node->children_[1]->children_[0]->str_len_ == 4 && + (0 == strcmp(node->children_[1]->children_[0]->str_value_, "cast")) && + node->children_[1]->children_[1]->num_child_ == 2 // T_EXPR_LIST node + && node->children_[1]->children_[1]->children_[1]->int16_values_[OB_NODE_CAST_TYPE_IDX] == T_VARCHAR && + node->children_[1]->children_[1]->children_[1]->int16_values_[OB_NODE_CAST_COLL_IDX] == BINARY_COLLATION) { + IS_NO_BACKSLASH_ESCAPES(ctx_.session_info_->get_sql_mode(), no_escapes); + } if (OB_FAIL(process_datatype_or_questionmark(escape_node, escape_expr))) { LOG_WARN("fail to resolver defalut excape node", K(ret)); } else if (OB_FAIL(t_expr->add_param_expr(escape_expr))) { LOG_WARN("fail to set param expr"); - } else if (lib::is_oracle_mode()) { + } else if (lib::is_oracle_mode() || no_escapes) { // Oracle mode, if not specify escape, then no escape, but the implementation of like must contain escape // so we rewrite like without escape // c1 like '%x\x%' --> c1 like replace('%x\x%', '\','\\') escape '\' -> c1 like '%x\\x%' escape '\' diff --git a/src/sql/session/ob_basic_session_info.h b/src/sql/session/ob_basic_session_info.h index 7916995e0..1f422eac0 100644 --- a/src/sql/session/ob_basic_session_info.h +++ b/src/sql/session/ob_basic_session_info.h @@ -89,6 +89,18 @@ struct ObSessionNLSParams // oracle nls parameters #define CREATE_OBJ_PRINT_PARAM(session) (NULL != (session) ? (session)->create_obj_print_params() : ObObjPrintParams()) +// flag is a single bit, but marco(e.g., IS_NO_BACKSLASH_ESCAPES) compare two 64-bits int using '&'; +// if we directly assign the result to flag(single bit), only the last bit of the result is used, +// which is equal to 'flag = result & 1;'. +// So we first convert the result to bool(tmp_flag) and assign the bool to flag, which is equal to +// 'flag = result!=0;'. +#define GET_SQL_MODE_BIT(marco, sql_mode, flag) \ + do { \ + bool tmp_flag = false; \ + marco(sql_mode, tmp_flag); \ + flag = tmp_flag; \ + } while (0) + #ifndef NDEBUG #define CHECK_COMPATIBILITY_MODE(session) \ do { \