From 8129d41b24b4096caf9798af1edb0962785e8a79 Mon Sep 17 00:00:00 2001 From: obdev Date: Wed, 23 Nov 2022 13:05:40 +0000 Subject: [PATCH] fix hung when convert to character for partition. --- src/rootserver/ob_ddl_service.cpp | 118 +++++++++++++++++++++----- src/rootserver/ob_ddl_service.h | 3 +- src/share/ob_ddl_common.h | 6 ++ src/share/schema/ob_schema_struct.cpp | 67 +++++++++++++++ src/share/schema/ob_schema_struct.h | 4 + 5 files changed, 178 insertions(+), 20 deletions(-) diff --git a/src/rootserver/ob_ddl_service.cpp b/src/rootserver/ob_ddl_service.cpp index 59aa2faba..e57f25623 100644 --- a/src/rootserver/ob_ddl_service.cpp +++ b/src/rootserver/ob_ddl_service.cpp @@ -3374,19 +3374,6 @@ int ObDDLService::check_alter_table_index(const obrpc::ObAlterTableArg &alter_ta return ret; } -int ObDDLService::check_can_convert_to_character(const share::schema::ObColumnSchemaV2 &column_schema, bool &can_convert) -{ - int ret = OB_SUCCESS; - can_convert = false; - if (OB_UNLIKELY(!column_schema.is_valid())) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid arguments", K(ret), K(column_schema)); - } else { - can_convert = (column_schema.is_string_type() || column_schema.is_enum_or_set()) && CS_TYPE_BINARY != column_schema.get_collation_type(); - } - return ret; -} - int ObDDLService::check_convert_to_character(obrpc::ObAlterTableArg &alter_table_arg, const ObTableSchema &orig_table_schema, ObDDLType &ddl_type) @@ -3421,9 +3408,7 @@ int ObDDLService::check_convert_to_character(obrpc::ObAlterTableArg &alter_table if (OB_ISNULL(col)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("col is NULL", K(ret)); - } else if (OB_FAIL(check_can_convert_to_character(*col, can_convert))) { - LOG_WARN("check can convert to character", K(ret)); - } else if (can_convert) { + } else if (ObDDLUtil::check_can_convert_character(col->get_meta_type())) { if (orig_table_schema.is_column_in_foreign_key(col->get_column_id())) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "Alter column charset or collation with foreign key"); @@ -3577,6 +3562,93 @@ int ObDDLService::alter_table_partition_by( return ret; } +// convert character set for ObBasePartition, inluding high_bound_val and list_row_values. +int ObDDLService::convert_to_character_for_partition( + const ObCollationType &to_collation, + ObTableSchema &new_table_schema) +{ + int ret = OB_SUCCESS; + const ObPartitionLevel part_level = new_table_schema.get_part_level(); + const ObPartitionFuncType part_func_type = new_table_schema.get_part_option().get_part_func_type(); + const ObPartitionFuncType subpart_func_type = new_table_schema.get_sub_part_option().get_sub_part_func_type(); + if (PARTITION_LEVEL_MAX <= part_level) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(part_level), K(new_table_schema)); + } else if (PARTITION_LEVEL_ZERO == part_level) { + // non-partitioned, do nothing. + } else { + const int64_t part_num = new_table_schema.get_partition_num(); + ObPartition **part_array = new_table_schema.get_part_array(); + if (OB_ISNULL(part_array)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null first part array", K(ret), K(part_level), K(part_num), K(part_func_type)); + } + // for the first-level part. + for (int64_t i = 0; OB_SUCC(ret) && i < part_num; i++) { + ObPartition *partition = part_array[i]; + if (OB_ISNULL(partition)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected err", K(ret)); + } else if (PARTITION_FUNC_TYPE_RANGE_COLUMNS == part_func_type + && OB_FAIL(partition->convert_character_for_range_columns_part(to_collation))) { + LOG_WARN("convert charset failed", K(ret), K(to_collation)); + } else if (PARTITION_FUNC_TYPE_LIST_COLUMNS == part_func_type + && OB_FAIL(partition->convert_character_for_list_columns_part(to_collation))) { + LOG_WARN("convert charset failed", K(ret), K(to_collation)); + } else if (PARTITION_LEVEL_TWO == part_level) { + // for the second-level part. + const int64_t subpart_num = partition->get_subpartition_num(); + ObSubPartition **subpart_array = partition->get_subpart_array(); + if (OB_ISNULL(subpart_array)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("part array is null", K(ret)); + } else if (subpart_num < 1) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sub_part_num less than 1", K(ret)); + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < subpart_num; j++) { + ObSubPartition *subpart = subpart_array[j]; + if (OB_ISNULL(subpart)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected err", K(ret)); + } else if (PARTITION_FUNC_TYPE_RANGE_COLUMNS == subpart_func_type + && OB_FAIL(subpart->convert_character_for_range_columns_part(to_collation))) { + LOG_WARN("convert charset failed", K(ret), K(to_collation)); + } else if (PARTITION_FUNC_TYPE_LIST_COLUMNS == subpart_func_type + && OB_FAIL(subpart->convert_character_for_list_columns_part(to_collation))) { + LOG_WARN("convert charset failed", K(ret), K(to_collation)); + } + } + } + } + } + } + // for def subpartition array. + if (OB_SUCC(ret) && new_table_schema.has_sub_part_template_def()) { + ObSubPartition **def_subpart_array = new_table_schema.get_def_subpart_array(); + const int64_t def_subpart_num = new_table_schema.get_def_sub_part_num(); + if (OB_ISNULL(def_subpart_array)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected err, def subpart arr is null", K(ret), K(new_table_schema)); + } else { + ObSubPartition *subpart_info = nullptr; + for (int64_t i = 0; OB_SUCC(ret) && i < def_subpart_num; i++) { + if (OB_ISNULL(subpart_info = def_subpart_array[i])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sub part is nullptr", K(ret)); + } else if (PARTITION_FUNC_TYPE_RANGE_COLUMNS == subpart_func_type + && OB_FAIL(subpart_info->convert_character_for_range_columns_part(to_collation))) { + LOG_WARN("convert charset failed", K(ret), K(to_collation)); + } else if (PARTITION_FUNC_TYPE_LIST_COLUMNS == subpart_func_type + && OB_FAIL(subpart_info->convert_character_for_list_columns_part(to_collation))) { + LOG_WARN("convert charset failed", K(ret), K(to_collation)); + } + } + } + } + return ret; +} + int ObDDLService::convert_to_character( obrpc::ObAlterTableArg &alter_table_arg, const ObTableSchema &orig_table_schema, @@ -3599,15 +3671,16 @@ int ObDDLService::convert_to_character( ObTableSchema::const_column_iterator tmp_end = orig_table_schema.column_end(); if (OB_FAIL(orig_table_schema.check_if_oracle_compat_mode(is_oracle_mode))) { LOG_WARN("failed to get oracle mode", K(ret)); + } else if (is_oracle_mode) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected compat mode", K(ret), K(orig_table_schema)); } else { for (; OB_SUCC(ret) && tmp_begin != tmp_end; tmp_begin++) { ObColumnSchemaV2 *orig_col = (*tmp_begin); if (OB_ISNULL(orig_col)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("col is NULL", K(ret)); - } else if (OB_FAIL(check_can_convert_to_character(*orig_col, can_convert))) { - LOG_WARN("check can convert to character", K(ret)); - } else if (can_convert) { + } else if (ObDDLUtil::check_can_convert_character(orig_col->get_meta_type())) { ObColumnSchemaV2 *col = new_table_schema.get_column_schema(orig_col->get_column_name()); if (OB_ISNULL(col)) { ret = OB_ERR_UNEXPECTED; @@ -3625,6 +3698,13 @@ int ObDDLService::convert_to_character( } } } + // convert character set for partition. + if (OB_SUCC(ret)) { + if (OB_FAIL(convert_to_character_for_partition(collation_type, new_table_schema))) { + LOG_WARN("convert collation type for partition failed", K(ret)); + } + } + OZ (create_user_hidden_table(orig_table_schema, new_table_schema, &alter_table_arg.sequence_ddl_arg_, diff --git a/src/rootserver/ob_ddl_service.h b/src/rootserver/ob_ddl_service.h index d9e7b89da..87e1fe12e 100644 --- a/src/rootserver/ob_ddl_service.h +++ b/src/rootserver/ob_ddl_service.h @@ -1322,6 +1322,8 @@ private: const int64_t frozen_version, ObDDLOperator &ddl_operator, common::ObMySQLTransaction &trans); + int convert_to_character_for_partition(const ObCollationType &to_collation, + share::schema::ObTableSchema &new_table_schema); int convert_to_character(obrpc::ObAlterTableArg &alter_table_arg, const share::schema::ObTableSchema &orgin_table_schema, share::schema::ObTableSchema &new_table_schema, @@ -2147,7 +2149,6 @@ private: const int64_t part_id, const share::schema::ObPartition *&part); int check_table_pk(const share::schema::ObTableSchema &orig_table_schema); - int check_can_convert_to_character(const share::schema::ObColumnSchemaV2 &col_schema, bool &can_convert); int clean_global_context(const ObContextSchema &context_schema); int get_hard_code_system_table_schema_( diff --git a/src/share/ob_ddl_common.h b/src/share/ob_ddl_common.h index f588704c7..c72d81c44 100644 --- a/src/share/ob_ddl_common.h +++ b/src/share/ob_ddl_common.h @@ -276,6 +276,12 @@ public: } static bool need_remote_write(const int ret_code); + static int check_can_convert_character(const ObObjMeta &obj_meta) + { + return (obj_meta.is_string_type() || obj_meta.is_enum_or_set()) + && CS_TYPE_BINARY != obj_meta.get_collation_type(); + } + private: static int generate_column_name_str( const common::ObIArray &column_names, diff --git a/src/share/schema/ob_schema_struct.cpp b/src/share/schema/ob_schema_struct.cpp index 26cf9d5da..73d774614 100644 --- a/src/share/schema/ob_schema_struct.cpp +++ b/src/share/schema/ob_schema_struct.cpp @@ -22,6 +22,7 @@ #include "lib/string/ob_sql_string.h" #include "lib/number/ob_number_v2.h" #include "common/ob_zone_type.h" +#include "share/ob_ddl_common.h" #include "share/schema/ob_table_schema.h" #include "share/ob_primary_zone_util.h" #include "sql/ob_sql_utils.h" @@ -5401,6 +5402,72 @@ int ObBasePartition::set_high_bound_val_with_hex_str( return ret; } +int ObBasePartition::convert_character_for_range_columns_part( + const ObCollationType &to_collation) +{ + int ret = OB_SUCCESS; + ObIAllocator *allocator = get_allocator(); + if (OB_ISNULL(allocator)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null allocator", K(ret)); + } else if (low_bound_val_.get_obj_cnt() > 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("defensive code, unexpected error", K(ret), K(low_bound_val_)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < high_bound_val_.get_obj_cnt(); i++) { + ObObj &obj = high_bound_val_.get_obj_ptr()[i]; + const ObObjMeta &obj_meta = obj.get_meta(); + if (obj_meta.is_lob()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected err, lob column can not be part key", K(ret), K(obj_meta)); + } else if (ObDDLUtil::check_can_convert_character(obj_meta)) { + ObString dst_string; + if (OB_FAIL(ObCharset::charset_convert(*allocator, obj.get_string(), obj.get_collation_type(), + to_collation, dst_string))) { + LOG_WARN("charset convert failed", K(ret), K(obj), K(to_collation)); + } else { + obj.set_string(obj.get_type(), dst_string); + obj.set_collation_type(to_collation); + } + } + } + } + return ret; +} + +int ObBasePartition::convert_character_for_list_columns_part( + const ObCollationType &to_collation) +{ + int ret = OB_SUCCESS; + ObIAllocator *allocator = get_allocator(); + if (OB_ISNULL(allocator)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null allocator", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < list_row_values_.count(); i++) { + common::ObNewRow &row = list_row_values_.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < row.get_count(); j++) { + ObObj &obj = row.get_cell(j); + const ObObjMeta &obj_meta = obj.get_meta(); + if (obj_meta.is_lob()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected err, lob column can not be part key", K(ret), K(obj_meta)); + } else if (ObDDLUtil::check_can_convert_character(obj_meta)) { + ObString dst_string; + if (OB_FAIL(ObCharset::charset_convert(*allocator, obj.get_string(), obj.get_collation_type(), + to_collation, dst_string))) { + LOG_WARN("charset convert failed", K(ret), K(obj), K(to_collation)); + } else { + obj.set_string(obj.get_type(), dst_string); + obj.set_collation_type(to_collation); + } + } + } + } + } + return ret; +} + OB_DEF_SERIALIZE(ObBasePartition) { int ret = OB_SUCCESS; diff --git a/src/share/schema/ob_schema_struct.h b/src/share/schema/ob_schema_struct.h index eacf2c46f..ee8a97fd6 100644 --- a/src/share/schema/ob_schema_struct.h +++ b/src/share/schema/ob_schema_struct.h @@ -1939,6 +1939,10 @@ public: PartitionType get_partition_type() const { return partition_type_; } virtual bool is_normal_partition() const = 0; virtual bool is_hidden_partition() const { return share::schema::is_hidden_partition(partition_type_); } + + // convert character set. + int convert_character_for_range_columns_part(const ObCollationType &to_collation); + int convert_character_for_list_columns_part(const ObCollationType &to_collation); VIRTUAL_TO_STRING_KV(K_(tenant_id), K_(table_id), K_(part_id), K_(name), K_(low_bound_val), K_(high_bound_val), K_(list_row_values), K_(part_idx), K_(is_empty_partition_name), K_(tablet_id));