From c63282a624e464f56845e293a502038aee37822f Mon Sep 17 00:00:00 2001 From: SevenJ-swj Date: Tue, 10 Oct 2023 11:40:07 +0000 Subject: [PATCH] support oms ncharacter_set_connection --- src/observer/mysql/ob_query_driver.cpp | 37 +++++++++- src/observer/mysql/obmp_base.cpp | 9 +++ src/observer/mysql/obmp_stmt_execute.cpp | 18 ++++- src/observer/mysql/obmp_stmt_execute.h | 2 + .../virtual_table/ob_session_variables.cpp | 1 + src/pl/ob_pl_type.cpp | 2 +- .../system_variable/ob_sys_var_class_type.h | 1 + .../system_variable/ob_system_variable.cpp | 2 + .../ob_system_variable_alias.h | 1 + .../ob_system_variable_factory.cpp | 26 ++++++- .../ob_system_variable_factory.h | 9 ++- .../ob_system_variable_init.cpp | 20 +++++- .../ob_system_variable_init.json | 18 +++++ src/sql/engine/expr/ob_expr_unistr.cpp | 6 +- src/sql/engine/expr/ob_expr_unistr.h | 5 ++ src/sql/parser/ob_fast_parser.cpp | 15 +++- src/sql/resolver/ob_resolver_utils.cpp | 70 ++++++++++++------- src/sql/session/ob_basic_session_info.cpp | 14 +++- src/sql/session/ob_basic_session_info.h | 12 +++- 19 files changed, 226 insertions(+), 42 deletions(-) diff --git a/src/observer/mysql/ob_query_driver.cpp b/src/observer/mysql/ob_query_driver.cpp index ef5b4f7239..e78617038b 100644 --- a/src/observer/mysql/ob_query_driver.cpp +++ b/src/observer/mysql/ob_query_driver.cpp @@ -352,9 +352,22 @@ int ObQueryDriver::convert_string_value_charset(ObObj& value, ObResultSet &resul ObArenaAllocator *allocator = NULL; ObCollationType from_collation_type = value.get_collation_type(); ObCollationType to_collation_type = CS_TYPE_INVALID; - if (OB_FAIL(my_session.get_character_set_results(charset_type))) { + ObCharsetType nchar = CHARSET_INVALID; + if (OB_FAIL(my_session.get_ncharacter_set_connection(nchar))) { + LOG_WARN("get ncharacter set connection failed", K(ret)); + } else if (lib::is_oracle_mode() + && (value.is_nchar() || value.is_nvarchar2()) + && nchar != CHARSET_INVALID + && nchar != CHARSET_BINARY) { + to_collation_type = ObCharset::get_default_collation(nchar); + charset_type = nchar; + } else if (OB_FAIL(my_session.get_character_set_results(charset_type))) { LOG_WARN("fail to get result charset", K(ret)); - } else if (from_collation_type == (to_collation_type = ObCharset::get_default_collation(charset_type))) { + } else { + to_collation_type = ObCharset::get_default_collation(charset_type); + } + if (OB_FAIL(ret)) { + } else if (from_collation_type == to_collation_type) { const ObCharsetInfo *charset_info = ObCharset::get_charset(from_collation_type); if (OB_ISNULL(charset_info)) { ret = OB_ERR_UNEXPECTED; @@ -419,6 +432,7 @@ int ObQueryDriver::convert_lob_value_charset(common::ObObj& value, sql::ObResult int ret = OB_SUCCESS; ObCharsetType charset_type = CHARSET_INVALID; + ObCharsetType nchar = CHARSET_INVALID; const ObSQLSessionInfo &my_session = result.get_session(); ObArenaAllocator *allocator = NULL; if (OB_FAIL(result.get_exec_context().get_convert_charset_allocator(allocator))) { @@ -428,6 +442,15 @@ int ObQueryDriver::convert_lob_value_charset(common::ObObj& value, sql::ObResult LOG_WARN("lob fake allocator is null.", K(ret), K(value)); } else if (OB_FAIL(my_session.get_character_set_results(charset_type))) { LOG_WARN("fail to get result charset", K(ret)); + } else if (OB_FAIL(my_session.get_ncharacter_set_connection(nchar))) { + LOG_WARN("get ncharacter set connection failed", K(ret)); + } else if (lib::is_oracle_mode() + && (value.is_nchar() || value.is_nvarchar2()) + && nchar != CHARSET_INVALID + && nchar != CHARSET_BINARY) { + charset_type = nchar; + } + if (OB_FAIL(ret)) { } else if (OB_FAIL(convert_lob_value_charset(value, charset_type, *allocator))) { LOG_WARN("convert lob value fail.", K(ret), K(value)); } @@ -438,6 +461,7 @@ int ObQueryDriver::convert_text_value_charset(common::ObObj& value, sql::ObResul { int ret = OB_SUCCESS; ObCharsetType charset_type = CHARSET_INVALID; + ObCharsetType nchar = CHARSET_INVALID; const ObSQLSessionInfo &my_session = result.get_session(); ObArenaAllocator *allocator = NULL; if (OB_FAIL(result.get_exec_context().get_convert_charset_allocator(allocator))) { @@ -447,6 +471,15 @@ int ObQueryDriver::convert_text_value_charset(common::ObObj& value, sql::ObResul LOG_WARN("text fake allocator is null.", K(ret), K(value)); } else if (OB_FAIL(my_session.get_character_set_results(charset_type))) { LOG_WARN("fail to get result charset", K(ret)); + } else if (OB_FAIL(my_session.get_ncharacter_set_connection(nchar))) { + LOG_WARN("get ncharacter set connection failed", K(ret)); + } else if (lib::is_oracle_mode() + && (value.is_nchar() || value.is_nvarchar2()) + && nchar != CHARSET_INVALID + && nchar != CHARSET_BINARY) { + charset_type = nchar; + } + if (OB_FAIL(ret)) { } else if (OB_FAIL(convert_text_value_charset(value, charset_type, *allocator, &my_session))) { LOG_WARN("convert lob value fail.", K(ret), K(value)); } diff --git a/src/observer/mysql/obmp_base.cpp b/src/observer/mysql/obmp_base.cpp index d4fd38d2f3..43c6074703 100644 --- a/src/observer/mysql/obmp_base.cpp +++ b/src/observer/mysql/obmp_base.cpp @@ -523,6 +523,7 @@ int ObMPBase::response_row(ObSQLSessionInfo &session, for (int64_t i = 0; OB_SUCC(ret) && i < tmp_row.get_count(); ++i) { ObObj &value = tmp_row.get_cell(i); ObCharsetType charset_type = CHARSET_INVALID; + ObCharsetType ncharset_type = CHARSET_INVALID; // need at ps mode if (value.get_type() != fields->at(i).type_.get_type()) { ObCastCtx cast_ctx(&allocator, NULL, CM_WARN_ON_FAIL, fields->at(i).type_.get_collation_type()); @@ -537,7 +538,15 @@ int ObMPBase::response_row(ObSQLSessionInfo &session, if (OB_FAIL(ret)) { } else if (OB_FAIL(session.get_character_set_results(charset_type))) { LOG_WARN("fail to get result charset", K(ret)); + } else if (OB_FAIL(session.get_ncharacter_set_connection(ncharset_type))) { + LOG_WARN("fail to get result charset", K(ret)); } else { + if (lib::is_oracle_mode() + && (value.is_nchar() || value.is_nvarchar2()) + && ncharset_type != CHARSET_INVALID + && ncharset_type != CHARSET_BINARY) { + charset_type = ncharset_type; + } if (ob_is_string_tc(value.get_type()) && CS_TYPE_INVALID != value.get_collation_type() && OB_FAIL(value.convert_string_value_charset(charset_type, allocator))) { diff --git a/src/observer/mysql/obmp_stmt_execute.cpp b/src/observer/mysql/obmp_stmt_execute.cpp index 34a9ce846e..824c1e90f4 100644 --- a/src/observer/mysql/obmp_stmt_execute.cpp +++ b/src/observer/mysql/obmp_stmt_execute.cpp @@ -714,6 +714,7 @@ int ObMPStmtExecute::parse_request_param_value(ObIAllocator &alloc, { int ret = OB_SUCCESS; ObCharsetType charset = CHARSET_INVALID; + ObCharsetType ncharset = CHARSET_INVALID; ObCollationType cs_conn = CS_TYPE_INVALID; ObCollationType cs_server = CS_TYPE_INVALID; if (OB_ISNULL(session)) { @@ -725,6 +726,8 @@ int ObMPStmtExecute::parse_request_param_value(ObIAllocator &alloc, LOG_WARN("get charset for client failed", K(ret)); } else if (OB_FAIL(session->get_collation_server(cs_server))) { LOG_WARN("get charset for client failed", K(ret)); + } else if (OB_FAIL(session->get_ncharacter_set_connection(ncharset))) { + LOG_WARN("get charset for client failed", K(ret)); } // Step5: decode value ObObjType ob_type; @@ -739,6 +742,7 @@ int ObMPStmtExecute::parse_request_param_value(ObIAllocator &alloc, if (OB_FAIL(parse_param_value(alloc, param_type, charset, + ncharset, is_oracle_mode() ? cs_server : cs_conn, session->get_nls_collation_nation(), pos, @@ -2124,6 +2128,7 @@ int ObMPStmtExecute::parse_complex_param_value(ObIAllocator &allocator, int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator, const uint32_t type, const ObCharsetType charset, + const ObCharsetType ncharset, const ObCollationType cs_type, const ObCollationType ncs_type, const char *& data, @@ -2258,6 +2263,12 @@ int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator, ObString dst; uint64_t length = 0; ObCollationType cur_cs_type = ObCharset::get_default_collation(charset); + ObCollationType cur_ncs_type = ObCollationType::CS_TYPE_INVALID; + if (ncharset == ObCharsetType::CHARSET_INVALID || ncharset == ObCharsetType::CHARSET_BINARY) { + cur_ncs_type = ObCharset::get_default_collation(charset); + } else { + cur_ncs_type = ObCharset::get_default_collation(ncharset); + } if (OB_FAIL(ObMySQLUtil::get_length(data, length))) { LOG_ERROR("decode varchar param value failed", K(ret)); } else { @@ -2271,7 +2282,7 @@ int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator, LOG_WARN("input param len is over size", K(ret), K(length)); } else if (MYSQL_TYPE_OB_NVARCHAR2 == type || MYSQL_TYPE_OB_NCHAR == type) { - OZ(copy_or_convert_str(allocator, cur_cs_type, ncs_type, str, dst)); + OZ(copy_or_convert_str(allocator, cur_ncs_type, ncs_type, str, dst)); if (OB_SUCC(ret)) { MYSQL_TYPE_OB_NVARCHAR2 == type ? param.set_nvarchar2(dst) : param.set_nchar(dst); @@ -2469,6 +2480,7 @@ int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator, int ObMPStmtExecute::parse_param_value(ObIAllocator &allocator, const uint32_t type, const ObCharsetType charset, + const ObCharsetType ncharset, const ObCollationType cs_type, const ObCollationType ncs_type, const char *&data, @@ -2512,7 +2524,7 @@ int ObMPStmtExecute::parse_param_value(ObIAllocator &allocator, } } else { bool is_unsigned = NULL == type_info || !type_info->elem_type_.get_meta_type().is_unsigned_integer() ? false : true; - if (OB_FAIL(parse_basic_param_value(allocator, type, charset, cs_type, ncs_type, + if (OB_FAIL(parse_basic_param_value(allocator, type, charset, ncharset, cs_type, ncs_type, data, tz_info, param, false, &analysis_checker_, is_unsigned))) { LOG_WARN("failed to parse basic param value", K(ret)); } else { @@ -2608,7 +2620,7 @@ int ObMPStmtExecute::parse_param_value(ObIAllocator &allocator, } else { const char* src = tmp; bool is_unsigned = NULL == type_info || !type_info->elem_type_.get_meta_type().is_unsigned_integer() ? false : true; - if (OB_FAIL(parse_basic_param_value(allocator, type, charset, cs_type, ncs_type, + if (OB_FAIL(parse_basic_param_value(allocator, type, charset, ncharset, cs_type, ncs_type, src, tz_info, param, false, NULL ,is_unsigned))) { LOG_WARN("failed to parse basic param value", K(ret)); } else { diff --git a/src/observer/mysql/obmp_stmt_execute.h b/src/observer/mysql/obmp_stmt_execute.h index 1d5b8a5b1e..d9240d5c6f 100644 --- a/src/observer/mysql/obmp_stmt_execute.h +++ b/src/observer/mysql/obmp_stmt_execute.h @@ -97,6 +97,7 @@ public: static int parse_basic_param_value(ObIAllocator &allocator, const uint32_t type, const ObCharsetType charset, + const ObCharsetType ncharset, const ObCollationType cs_type, const ObCollationType ncs_type, const char *& data, @@ -300,6 +301,7 @@ private: int parse_param_value(ObIAllocator& allocator, const uint32_t type, const ObCharsetType charset, + const ObCharsetType ncharset, const ObCollationType cs_type, const ObCollationType ncs_type, const char *&data, diff --git a/src/observer/virtual_table/ob_session_variables.cpp b/src/observer/virtual_table/ob_session_variables.cpp index 77fb937076..8edfc8e730 100644 --- a/src/observer/virtual_table/ob_session_variables.cpp +++ b/src/observer/virtual_table/ob_session_variables.cpp @@ -61,6 +61,7 @@ int ObSessionVariables::inner_get_next_row(ObNewRow *&row) ObString sys_var_show_str; for (int64_t i = 0; OB_SUCC(ret) && i < session_->get_sys_var_count(); ++i) { const ObBasicSysVar *sys_var = NULL; + if (OB_UNLIKELY(NULL == (sys_var = session_->get_sys_var(i)))) { ret = OB_ERR_UNEXPECTED; SERVER_LOG(WARN, "sys var is NULL", K(ret), K(i)); diff --git a/src/pl/ob_pl_type.cpp b/src/pl/ob_pl_type.cpp index 9aa3e56cdc..e17d8a1e92 100644 --- a/src/pl/ob_pl_type.cpp +++ b/src/pl/ob_pl_type.cpp @@ -1072,7 +1072,7 @@ int ObPLDataType::deserialize(ObSchemaGetterGuard &schema_guard, } else if (OB_FAIL(ObSMUtils::get_mysql_type(get_obj_type(), mysql_type, flags, num_decimals))) { LOG_WARN("get mysql type failed", K(ret)); } else if (OB_FAIL(ObMPStmtExecute::parse_basic_param_value( - allocator, (uint8_t)mysql_type, charset, cs_type, ncs_type, src, tz_info, param, true, NULL, + allocator, (uint8_t)mysql_type, charset, ObCharsetType::CHARSET_INVALID, cs_type, ncs_type, src, tz_info, param, true, NULL, NULL == get_data_type() ? false : get_data_type()->get_meta_type().is_unsigned_integer()))) { // get_data_type() is null, its a extend type, unsigned need false. LOG_WARN("failed to parse basic param value", K(ret)); diff --git a/src/share/system_variable/ob_sys_var_class_type.h b/src/share/system_variable/ob_sys_var_class_type.h index 32685f6ede..4b928c2da3 100644 --- a/src/share/system_variable/ob_sys_var_class_type.h +++ b/src/share/system_variable/ob_sys_var_class_type.h @@ -255,6 +255,7 @@ enum ObSysVarClassType SYS_VAR_RUNTIME_BLOOM_FILTER_MAX_SIZE = 10149, SYS_VAR_OPTIMIZER_FEATURES_ENABLE = 10150, SYS_VAR__OB_PROXY_WEAKREAD_FEEDBACK = 10151, + SYS_VAR_NCHARACTER_SET_CONNECTION = 10152, }; } diff --git a/src/share/system_variable/ob_system_variable.cpp b/src/share/system_variable/ob_system_variable.cpp index 7d54ac77b5..8505808381 100644 --- a/src/share/system_variable/ob_system_variable.cpp +++ b/src/share/system_variable/ob_system_variable.cpp @@ -2630,6 +2630,8 @@ int ObSysVarToStrFuncs::to_str_charset(ObIAllocator &allocator, } else if (OB_FAIL(sys_var.get_value().get_int(coll_type_int64))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid value", K(ret), K(sys_var), K(sys_var.get_value())); + } else if (coll_type_int64 == 0) { + result_str = ObString(""); } else if (OB_UNLIKELY(false == ObCharset::is_valid_collation(coll_type_int64))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid collation", K(ret), K(coll_type_int64), K(sys_var)); diff --git a/src/share/system_variable/ob_system_variable_alias.h b/src/share/system_variable/ob_system_variable_alias.h index a019e8bcb8..777a391a7a 100644 --- a/src/share/system_variable/ob_system_variable_alias.h +++ b/src/share/system_variable/ob_system_variable_alias.h @@ -250,6 +250,7 @@ namespace share static const char* const OB_SV_RUNTIME_BLOOM_FILTER_MAX_SIZE = "runtime_bloom_filter_max_size"; static const char* const OB_SV_OPTIMIZER_FEATURES_ENABLE = "optimizer_features_enable"; static const char* const OB_SV__OB_PROXY_WEAKREAD_FEEDBACK = "_ob_proxy_weakread_feedback"; + static const char* const OB_SV_NCHARACTER_SET_CONNECTION = "ncharacter_set_connection"; } } diff --git a/src/share/system_variable/ob_system_variable_factory.cpp b/src/share/system_variable/ob_system_variable_factory.cpp index 4cca45e361..1fc150661c 100644 --- a/src/share/system_variable/ob_system_variable_factory.cpp +++ b/src/share/system_variable/ob_system_variable_factory.cpp @@ -215,6 +215,7 @@ const char *ObSysVarFactory::SYS_VAR_NAMES_SORTED_BY_NAME[] = { "max_execution_time", "max_sp_recursion_depth", "max_user_connections", + "ncharacter_set_connection", "net_buffer_length", "net_read_timeout", "net_write_timeout", @@ -452,6 +453,7 @@ const ObSysVarClassType ObSysVarFactory::SYS_VAR_IDS_SORTED_BY_NAME[] = { SYS_VAR_MAX_EXECUTION_TIME, SYS_VAR_MAX_SP_RECURSION_DEPTH, SYS_VAR_MAX_USER_CONNECTIONS, + SYS_VAR_NCHARACTER_SET_CONNECTION, SYS_VAR_NET_BUFFER_LENGTH, SYS_VAR_NET_READ_TIMEOUT, SYS_VAR_NET_WRITE_TIMEOUT, @@ -830,7 +832,8 @@ const char *ObSysVarFactory::SYS_VAR_NAMES_SORTED_BY_ID[] = { "runtime_filter_max_in_num", "runtime_bloom_filter_max_size", "optimizer_features_enable", - "_ob_proxy_weakread_feedback" + "_ob_proxy_weakread_feedback", + "ncharacter_set_connection" }; bool ObSysVarFactory::sys_var_name_case_cmp(const char *name1, const ObString &name2) @@ -1233,6 +1236,7 @@ int ObSysVarFactory::create_all_sys_vars() + sizeof(ObSysVarRuntimeBloomFilterMaxSize) + sizeof(ObSysVarOptimizerFeaturesEnable) + sizeof(ObSysVarObProxyWeakreadFeedback) + + sizeof(ObSysVarNcharacterSetConnection) ; void *ptr = NULL; if (OB_ISNULL(ptr = allocator_.alloc(total_mem_size))) { @@ -3347,6 +3351,15 @@ int ObSysVarFactory::create_all_sys_vars() ptr = (void *)((char *)ptr + sizeof(ObSysVarObProxyWeakreadFeedback)); } } + if (OB_SUCC(ret)) { + if (OB_ISNULL(sys_var_ptr = new (ptr)ObSysVarNcharacterSetConnection())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("fail to new ObSysVarNcharacterSetConnection", K(ret)); + } else { + store_buf_[ObSysVarsToIdxMap::get_store_idx(static_cast(SYS_VAR_NCHARACTER_SET_CONNECTION))] = sys_var_ptr; + ptr = (void *)((char *)ptr + sizeof(ObSysVarNcharacterSetConnection)); + } + } } return ret; @@ -5931,6 +5944,17 @@ int ObSysVarFactory::create_sys_var(ObIAllocator &allocator_, ObSysVarClassType } break; } + case SYS_VAR_NCHARACTER_SET_CONNECTION: { + void *ptr = NULL; + if (OB_ISNULL(ptr = allocator_.alloc(sizeof(ObSysVarNcharacterSetConnection)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("fail to alloc memory", K(ret), K(sizeof(ObSysVarNcharacterSetConnection))); + } else if (OB_ISNULL(sys_var_ptr = new (ptr)ObSysVarNcharacterSetConnection())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("fail to new ObSysVarNcharacterSetConnection", K(ret)); + } + break; + } default: { ret = OB_ERR_UNEXPECTED; diff --git a/src/share/system_variable/ob_system_variable_factory.h b/src/share/system_variable/ob_system_variable_factory.h index f6f7a4e9da..d07167e608 100644 --- a/src/share/system_variable/ob_system_variable_factory.h +++ b/src/share/system_variable/ob_system_variable_factory.h @@ -1691,6 +1691,13 @@ public: inline virtual ObSysVarClassType get_type() const { return SYS_VAR__OB_PROXY_WEAKREAD_FEEDBACK; } inline virtual const common::ObObj &get_global_default_value() const { return ObSysVariables::get_default_value(233); } }; +class ObSysVarNcharacterSetConnection : public ObCharsetSysVar +{ +public: + ObSysVarNcharacterSetConnection() : ObCharsetSysVar(ObSysVarOnCheckFuncs::check_and_convert_charset, NULL, ObSysVarToObjFuncs::to_obj_charset, ObSysVarToStrFuncs::to_str_charset, ObSysVarGetMetaTypeFuncs::get_meta_type_varchar) {} + inline virtual ObSysVarClassType get_type() const { return SYS_VAR_NCHARACTER_SET_CONNECTION; } + inline virtual const common::ObObj &get_global_default_value() const { return ObSysVariables::get_default_value(234); } +}; class ObSysVarFactory @@ -1711,7 +1718,7 @@ public: static const common::ObString get_sys_var_name_by_id(ObSysVarClassType sys_var_id); const static int64_t MYSQL_SYS_VARS_COUNT = 97; - const static int64_t OB_SYS_VARS_COUNT = 137; + const static int64_t OB_SYS_VARS_COUNT = 138; const static int64_t ALL_SYS_VARS_COUNT = MYSQL_SYS_VARS_COUNT + OB_SYS_VARS_COUNT; const static int64_t INVALID_MAX_READ_STALE_TIME = -1; diff --git a/src/share/system_variable/ob_system_variable_init.cpp b/src/share/system_variable/ob_system_variable_init.cpp index f6b983bb46..954ffa2d21 100644 --- a/src/share/system_variable/ob_system_variable_init.cpp +++ b/src/share/system_variable/ob_system_variable_init.cpp @@ -3305,13 +3305,31 @@ static struct VarsInit{ ObSysVars[233].alias_ = "OB_SV__OB_PROXY_WEAKREAD_FEEDBACK" ; }(); + [&] (){ + ObSysVars[234].default_value_ = "0" ; + ObSysVars[234].info_ = "The national character set which should be translated to after receiving the statement" ; + ObSysVars[234].name_ = "ncharacter_set_connection" ; + ObSysVars[234].data_type_ = ObIntType ; + ObSysVars[234].to_show_str_func_ = "ObSysVarToStrFuncs::to_str_charset" ; + ObSysVars[234].flags_ = ObSysVarFlag::SESSION_SCOPE | ObSysVarFlag::NEED_SERIALIZE | ObSysVarFlag::INVISIBLE | ObSysVarFlag::NULLABLE ; + ObSysVars[234].base_class_ = "ObCharsetSysVar" ; + ObSysVars[234].to_select_obj_func_ = "ObSysVarToObjFuncs::to_obj_charset" ; + ObSysVars[234].on_check_and_convert_func_ = "ObSysVarOnCheckFuncs::check_and_convert_charset" ; + ObSysVars[234].id_ = SYS_VAR_NCHARACTER_SET_CONNECTION ; + cur_max_var_id = MAX(cur_max_var_id, static_cast(SYS_VAR_NCHARACTER_SET_CONNECTION)) ; + ObSysVarsIdToArrayIdx[SYS_VAR_NCHARACTER_SET_CONNECTION] = 234 ; + ObSysVars[234].get_meta_type_func_ = "ObSysVarGetMetaTypeFuncs::get_meta_type_varchar" ; + ObSysVars[234].base_value_ = "0" ; + ObSysVars[234].alias_ = "OB_SV_NCHARACTER_SET_CONNECTION" ; + }(); + if (cur_max_var_id >= ObSysVarFactory::OB_MAX_SYS_VAR_ID) { HasInvalidSysVar = true; } } }vars_init; -static int64_t var_amount = 234; +static int64_t var_amount = 235; int64_t ObSysVariables::get_all_sys_var_count(){ return ObSysVarFactory::ALL_SYS_VARS_COUNT;} ObSysVarClassType ObSysVariables::get_sys_var_id(int64_t i){ return ObSysVars[i].id_;} diff --git a/src/share/system_variable/ob_system_variable_init.json b/src/share/system_variable/ob_system_variable_init.json index 5c00ab7575..f20d40bee3 100644 --- a/src/share/system_variable/ob_system_variable_init.json +++ b/src/share/system_variable/ob_system_variable_init.json @@ -3335,5 +3335,23 @@ "info_cn": "", "background_cn": "", "ref_url": "" + }, + "ncharacter_set_connection": { + "id": 10152, + "name": "ncharacter_set_connection", + "default_value": "0", + "base_value": "0", + "data_type": "int", + "info": "The national character set which should be translated to response nstring data", + "flags": "SESSION | NEED_SERIALIZE | INVISIBLE | NULL", + "on_check_and_convert_func": "ObSysVarOnCheckFuncs::check_and_convert_charset", + "get_meta_type_func": "ObSysVarGetMetaTypeFuncs::get_meta_type_varchar", + "to_select_obj_func": "ObSysVarToObjFuncs::to_obj_charset", + "to_show_str_func": "ObSysVarToStrFuncs::to_str_charset", + "base_class": "ObCharsetSysVar", + "publish_version": "430", + "info_cn": "", + "background_cn": "", + "ref_url": "" } } diff --git a/src/sql/engine/expr/ob_expr_unistr.cpp b/src/sql/engine/expr/ob_expr_unistr.cpp index c85f28e3a4..03e14800c5 100644 --- a/src/sql/engine/expr/ob_expr_unistr.cpp +++ b/src/sql/engine/expr/ob_expr_unistr.cpp @@ -54,9 +54,9 @@ int ObExprUnistr::calc_result_type1(ObExprResType &type, return ret; } -int calc_unistr(const ObString &src, - const ObCollationType src_cs_type, - const ObCollationType dst_cs_type, +int ObExprUnistr::calc_unistr(const common::ObString &src, + const common::ObCollationType src_cs_type, + const common::ObCollationType dst_cs_type, char* buf, const int64_t buf_len, int32_t &pos) { int ret = OB_SUCCESS; diff --git a/src/sql/engine/expr/ob_expr_unistr.h b/src/sql/engine/expr/ob_expr_unistr.h index e72cb686ef..d3527f57e5 100644 --- a/src/sql/engine/expr/ob_expr_unistr.h +++ b/src/sql/engine/expr/ob_expr_unistr.h @@ -30,7 +30,12 @@ public: virtual int cg_expr(ObExprCGCtx &op_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const; + static int calc_unistr(const common::ObString &src, + const common::ObCollationType src_cs_type, + const common::ObCollationType dst_cs_type, + char* buf, const int64_t buf_len, int32_t &pos); static int calc_unistr_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res_datum); + private: DISALLOW_COPY_AND_ASSIGN(ObExprUnistr); }; diff --git a/src/sql/parser/ob_fast_parser.cpp b/src/sql/parser/ob_fast_parser.cpp index b27956a41e..207b9b6315 100644 --- a/src/sql/parser/ob_fast_parser.cpp +++ b/src/sql/parser/ob_fast_parser.cpp @@ -2955,7 +2955,9 @@ int ObFastParserOracle::process_string(const bool in_q_quote) int64_t str_len = tmp_buf_len_; need_mem_size += str_len + 1; // '\0' if ('n' == raw_sql_.char_at(cur_token_begin_pos_) || - 'N' == raw_sql_.char_at(cur_token_begin_pos_)) { + 'N' == raw_sql_.char_at(cur_token_begin_pos_) || + 'u' == raw_sql_.char_at(cur_token_begin_pos_) || + 'U' == raw_sql_.char_at(cur_token_begin_pos_)) { param_type = T_NCHAR; } // allocate all the memory needed at once @@ -2980,6 +2982,11 @@ int ObFastParserOracle::process_string(const bool in_q_quote) } else { node->raw_sql_offset_ = cur_token_begin_pos_; } + + if ('u' == raw_sql_.char_at(cur_token_begin_pos_) || + 'U' == raw_sql_.char_at(cur_token_begin_pos_)) { + node->value_ = -1; + } lex_store_param(node, buf); } } @@ -3074,7 +3081,11 @@ int ObFastParserOracle::process_identifier(bool is_number_begin) } case 'u': // update case 'U': { - CHECK_AND_PROCESS_HINT("pdate", 5); + if ('\'' == raw_sql_.char_at(raw_sql_.cur_pos_)) { + OZ (process_string(false)); + } else { + CHECK_AND_PROCESS_HINT("pdate", 5); + } break; } case 'i': // insert or interval diff --git a/src/sql/resolver/ob_resolver_utils.cpp b/src/sql/resolver/ob_resolver_utils.cpp index 9435cb1971..4284234019 100644 --- a/src/sql/resolver/ob_resolver_utils.cpp +++ b/src/sql/resolver/ob_resolver_utils.cpp @@ -40,6 +40,7 @@ #include "sql/engine/expr/ob_datum_cast.h" #include "sql/parser/ob_parser_utils.h" #include "lib/json/ob_json_print_utils.h" +#include "sql/engine/expr/ob_expr_unistr.h" namespace oceanbase { @@ -2340,38 +2341,57 @@ int ObResolverUtils::resolve_const(const ParseNode *node, // 对于字符,此处使用的是连接里设置的字符集,在Oracle模式下,需要 // 转换成server使用的字符集,MySQL不需要 - if (OB_SUCC(ret) && - lib::is_oracle_mode()) { + if (OB_FAIL(ret)) { + // do nothing + } else if (lib::is_oracle_mode()) { ObCollationType target_collation = CS_TYPE_INVALID; if (T_NVARCHAR2 == node->type_ || T_NCHAR == node->type_) { target_collation = nchar_collation; } else { target_collation = server_collation; } - - // 为了解决部分gbk字符因为转换函数中不包含对应unicode字符导致全gbk链路中字符解析错误的问题, - // 当两个ObCollationType的CharsetType相同时,跳过 mb_wc, wc_mb 的转换过程, - // 直接设置结果的collation_type - if (ObCharset::charset_type_by_coll(connection_collation) == - ObCharset::charset_type_by_coll(target_collation)) { - val.set_collation_type(target_collation); + ObString str; + val.get_string(str); + char *buf = nullptr; + /* OB目前支持utf8、utf16、和gbk + * utf8mb4是1~4个字节,gbk是1到2,utf16是2或者4 + * 进行转换,极限情况是1个字节转成4个,所以这里放大了4倍 + */ + const int CharConvertFactorNum = 4; + int32_t buf_len = str.length() * CharConvertFactorNum; + uint32_t result_len = 0; + uint32_t incomplete_len = 0; + if (0 == buf_len) { + //do nothing + } else if (CS_TYPE_INVALID == target_collation) { + ret = OB_ERR_UNEXPECTED; + } + if (OB_FAIL(ret)) { + } else if (node->value_ == -1) { + // process u'string': connection_char->unicode->target_char + if (OB_UNLIKELY(node->type_ != T_NCHAR)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("u string is not nchar", K(ret)); + } else if (OB_ISNULL(buf = static_cast(allocator.alloc(buf_len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("alloc memory failed", K(ret), K(buf_len)); + } else if (OB_FAIL(ObExprUnistr::calc_unistr(str, connection_collation, target_collation, buf, buf_len, + (int32_t &)(result_len)))) { + LOG_WARN("calc unistr failed", K(ret)); + } else { + str.assign_ptr(buf, result_len); + val.set_string(val.get_type(), buf, result_len); + val.set_collation_type(nchar_collation); + val.set_collation_level(CS_LEVEL_COERCIBLE); + } } else { - ObString str; - val.get_string(str); - char *buf = nullptr; - /* OB目前支持utf8、utf16、和gbk - * utf8mb4是1~4个字节,gbk是1到2,utf16是2或者4 - * 进行转换,极限情况是1个字节转成4个,所以这里放大了4倍 - */ - int32_t buf_len = str.length() * ObCharset::CharConvertFactorNum; - uint32_t result_len = 0; - uint32_t incomplete_len = 0; - if (0 == buf_len) { - //do nothing - } else if (CS_TYPE_INVALID == target_collation) { - ret = OB_ERR_UNEXPECTED; - } else if (OB_UNLIKELY(nullptr == (buf = - static_cast(allocator.alloc(buf_len))))) { + // 为了解决部分gbk字符因为转换函数中不包含对应unicode字符导致全gbk链路中字符解析错误的问题, + // 当两个ObCollationType的CharsetType相同时,跳过 mb_wc, wc_mb 的转换过程, + // 直接设置结果的collation_type + if (ObCharset::charset_type_by_coll(connection_collation) == + ObCharset::charset_type_by_coll(target_collation)) { + val.set_collation_type(target_collation); + } else if (OB_ISNULL(buf = static_cast(allocator.alloc(buf_len)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("alloc memory failed", K(ret), K(buf_len)); } else { diff --git a/src/sql/session/ob_basic_session_info.cpp b/src/sql/session/ob_basic_session_info.cpp index 89faacf531..45f6ded461 100644 --- a/src/sql/session/ob_basic_session_info.cpp +++ b/src/sql/session/ob_basic_session_info.cpp @@ -3383,7 +3383,11 @@ int ObBasicSessionInfo::get_charset_sys_var(const ObSysVarClassType sys_var_id, } else if (OB_FAIL(val->get_value().get_int(coll_int64))) { LOG_ERROR("fail to get int from value", K(*val), K(ret)); } else if (OB_UNLIKELY(false == ObCharset::is_valid_collation(coll_int64))) { - LOG_ERROR("invalid collation", K(sys_var_id), K(coll_int64), K(*val)); + if (SYS_VAR_NCHARACTER_SET_CONNECTION == sys_var_id && coll_int64 == 0) { + //do nothing + } else { + LOG_ERROR("invalid collation", K(sys_var_id), K(coll_int64), K(*val)); + } } else { cs_type = ObCharset::charset_type_by_coll(static_cast(coll_int64)); } @@ -5164,6 +5168,14 @@ int ObBasicSessionInfo::get_character_set_connection(ObCharsetType &character_se return OB_SUCCESS; } +int ObBasicSessionInfo::get_ncharacter_set_connection(ObCharsetType &ncharacter_set_connection) const +{ + if (CHARSET_INVALID == (ncharacter_set_connection = sys_vars_cache_.get_ncharacter_set_connection())) { + get_charset_sys_var(SYS_VAR_NCHARACTER_SET_CONNECTION, ncharacter_set_connection); + } + return OB_SUCCESS; +} + int ObBasicSessionInfo::get_character_set_database(ObCharsetType &character_set_database) const { return get_charset_sys_var(SYS_VAR_CHARACTER_SET_DATABASE, character_set_database); diff --git a/src/sql/session/ob_basic_session_info.h b/src/sql/session/ob_basic_session_info.h index 8237605060..d4c7768fe4 100644 --- a/src/sql/session/ob_basic_session_info.h +++ b/src/sql/session/ob_basic_session_info.h @@ -596,6 +596,7 @@ public: int get_div_precision_increment(int64_t &div_precision_increment) const; int get_character_set_client(common::ObCharsetType &character_set_client) const; int get_character_set_connection(common::ObCharsetType &character_set_connection) const; + int get_ncharacter_set_connection(common::ObCharsetType &ncharacter_set_connection) const; int get_character_set_database(common::ObCharsetType &character_set_database) const; int get_character_set_results(common::ObCharsetType &character_set_results) const; int get_character_set_server(common::ObCharsetType &character_set_server) const; @@ -1533,7 +1534,8 @@ public: runtime_filter_type_(0), runtime_filter_wait_time_ms_(0), runtime_filter_max_in_num_(0), - runtime_bloom_filter_max_size_(INT_MAX32) + runtime_bloom_filter_max_size_(INT_MAX32), + ncharacter_set_connection_(ObCharsetType::CHARSET_INVALID) { for (int64_t i = 0; i < ObNLSFormatEnum::NLS_MAX; ++i) { @@ -1593,6 +1595,7 @@ public: runtime_filter_wait_time_ms_ = 0; runtime_filter_max_in_num_ = 0; runtime_bloom_filter_max_size_ = INT32_MAX; + ncharacter_set_connection_ = ObCharsetType::CHARSET_INVALID; } inline bool operator==(const SysVarsCacheData &other) const { @@ -1635,7 +1638,8 @@ public: iso_nls_currency_ == other.iso_nls_currency_ && ob_plsql_ccflags_ == other.ob_plsql_ccflags_ && log_row_value_option_ == other.log_row_value_option_ && - ob_max_read_stale_time_ == other.ob_max_read_stale_time_; + ob_max_read_stale_time_ == other.ob_max_read_stale_time_ && + ncharacter_set_connection_ == other.ncharacter_set_connection_; bool equal2 = true; for (int64_t i = 0; i < ObNLSFormatEnum::NLS_MAX; ++i) { if (nls_formats_[i] != other.nls_formats_[i]) { @@ -1803,6 +1807,8 @@ public: int64_t runtime_filter_wait_time_ms_; int64_t runtime_filter_max_in_num_; int64_t runtime_bloom_filter_max_size_; + + ObCharsetType ncharacter_set_connection_; private: char nls_formats_buf_[ObNLSFormatEnum::NLS_MAX][MAX_NLS_FORMAT_STR_LEN]; }; @@ -1914,6 +1920,7 @@ private: DEF_SYS_VAR_CACHE_FUNCS(int64_t, runtime_filter_wait_time_ms); DEF_SYS_VAR_CACHE_FUNCS(int64_t, runtime_filter_max_in_num); DEF_SYS_VAR_CACHE_FUNCS(int64_t, runtime_bloom_filter_max_size); + DEF_SYS_VAR_CACHE_FUNCS(ObCharsetType, ncharacter_set_connection); void set_autocommit_info(bool inc_value) { inc_data_.autocommit_ = inc_value; @@ -1981,6 +1988,7 @@ private: bool inc_runtime_filter_wait_time_ms_:1; bool inc_runtime_filter_max_in_num_:1; bool inc_runtime_bloom_filter_max_size_:1; + bool inc_ncharacter_set_connection_:1; }; }; };