From 1ee64365eabe0817d3f5c60d6e00a9aadf72ab20 Mon Sep 17 00:00:00 2001 From: "791065426@qq.com" <791065426@qq.com> Date: Tue, 16 Apr 2024 07:19:48 +0000 Subject: [PATCH] [FEAT MERGE] Support exchanging partition between partitioned table A and non-partitioned table B. Co-authored-by: fkuner <784819644@qq.com> --- .../src/common/rowkey/ob_rowkey_info.cpp | 14 +- deps/oblib/src/common/rowkey/ob_rowkey_info.h | 1 + .../src/ob_cdc_multi_data_source_info.h | 3 +- .../src/ob_cdc_tablet_to_table_info.cpp | 139 +- .../src/ob_cdc_tablet_to_table_info.h | 68 +- .../libobcdc/src/ob_log_part_mgr.cpp | 32 + src/logservice/libobcdc/src/ob_log_part_mgr.h | 2 + .../libobcdc/src/ob_log_part_trans_task.cpp | 1 + .../libobcdc/src/ob_log_sequencer1.cpp | 10 + src/objit/include/objit/common/ob_item_type.h | 2 - src/observer/ob_srv_xlator_rootserver.cpp | 1 + src/rootserver/CMakeLists.txt | 1 + src/rootserver/ob_ddl_operator.cpp | 177 ++ src/rootserver/ob_ddl_operator.h | 26 + src/rootserver/ob_ddl_service.cpp | 18 +- src/rootserver/ob_ddl_service.h | 68 +- src/rootserver/ob_partition_exchange.cpp | 2670 +++++++++++++++++ src/rootserver/ob_partition_exchange.h | 296 ++ src/rootserver/ob_root_service.cpp | 40 + src/rootserver/ob_root_service.h | 1 + src/rootserver/ob_rs_rpc_processor.h | 1 + src/share/ob_common_rpc_proxy.h | 1 + src/share/ob_errno.def | 1 - src/share/ob_rpc_struct.cpp | 95 + src/share/ob_rpc_struct.h | 35 + src/share/schema/ob_column_schema.h | 1 + src/share/schema/ob_constraint.cpp | 14 + src/share/schema/ob_constraint.h | 1 + src/share/schema/ob_schema_struct.cpp | 14 + src/share/schema/ob_schema_struct.h | 1 + src/share/schema/ob_sequence_sql_service.cpp | 52 +- src/share/schema/ob_sequence_sql_service.h | 17 +- src/share/schema/ob_table_sql_service.cpp | 55 + src/share/schema/ob_table_sql_service.h | 14 + src/share/tablet/ob_tablet_to_ls_operator.cpp | 35 + src/share/tablet/ob_tablet_to_ls_operator.h | 5 + src/sql/engine/cmd/ob_table_executor.cpp | 42 +- src/sql/engine/cmd/ob_table_executor.h | 6 + .../parser/non_reserved_keywords_mysql_mode.c | 2 + src/sql/parser/sql_parser_mysql_mode.y | 10 +- .../resolver/ddl/ob_alter_table_resolver.cpp | 149 + .../resolver/ddl/ob_alter_table_resolver.h | 2 + src/sql/resolver/ddl/ob_alter_table_stmt.cpp | 9 + src/sql/resolver/ddl/ob_alter_table_stmt.h | 3 + .../ob_ddl_change_tablet_to_table_helper.h | 66 + .../compile_utility/mds_register.h | 6 +- 46 files changed, 4105 insertions(+), 102 deletions(-) create mode 100644 src/rootserver/ob_partition_exchange.cpp create mode 100644 src/rootserver/ob_partition_exchange.h create mode 100644 src/storage/ddl/ob_ddl_change_tablet_to_table_helper.h diff --git a/deps/oblib/src/common/rowkey/ob_rowkey_info.cpp b/deps/oblib/src/common/rowkey/ob_rowkey_info.cpp index 4021c4f9c..ec1690073 100644 --- a/deps/oblib/src/common/rowkey/ob_rowkey_info.cpp +++ b/deps/oblib/src/common/rowkey/ob_rowkey_info.cpp @@ -70,6 +70,14 @@ DEFINE_GET_SERIALIZE_SIZE(ObRowkeyColumn) len += serialization::encoded_length_vi32(order_); return len; } +bool ObRowkeyColumn::is_equal_except_column_id(const ObRowkeyColumn &other) const +{ + return length_ == other.length_ && + type_ == other.type_ && + order_ == other.order_ && + fulltext_flag_ == other.fulltext_flag_ && + spatial_flag_ == other.spatial_flag_; +} ObRowkeyColumn& ObRowkeyColumn::operator=(const ObRowkeyColumn &other) { @@ -85,12 +93,8 @@ ObRowkeyColumn& ObRowkeyColumn::operator=(const ObRowkeyColumn &other) bool ObRowkeyColumn::operator==(const ObRowkeyColumn &other) const { return - this->length_ == other.length_ && this->column_id_ == other.column_id_ && - this->type_ == other.type_ && - this->order_ == other.order_ && - this->fulltext_flag_ == other.fulltext_flag_ && - this->spatial_flag_ == other.spatial_flag_; + this->is_equal_except_column_id(other); } ObRowkeyInfo::ObRowkeyInfo() diff --git a/deps/oblib/src/common/rowkey/ob_rowkey_info.h b/deps/oblib/src/common/rowkey/ob_rowkey_info.h index 402a23df5..f763a9a47 100644 --- a/deps/oblib/src/common/rowkey/ob_rowkey_info.h +++ b/deps/oblib/src/common/rowkey/ob_rowkey_info.h @@ -36,6 +36,7 @@ struct ObRowkeyColumn return (ObURowIDType == type_.get_type() || length_ >= 0) && common::OB_INVALID_ID != column_id_ && common::ob_is_valid_obj_type(static_cast(type_.get_type())); } + bool is_equal_except_column_id(const ObRowkeyColumn &other) const; ObRowkeyColumn &operator=(const ObRowkeyColumn &other); bool operator==(const ObRowkeyColumn &other) const; const ObObjMeta get_meta_type() const { return type_; } diff --git a/src/logservice/libobcdc/src/ob_cdc_multi_data_source_info.h b/src/logservice/libobcdc/src/ob_cdc_multi_data_source_info.h index d802283a6..c52392a50 100644 --- a/src/logservice/libobcdc/src/ob_cdc_multi_data_source_info.h +++ b/src/logservice/libobcdc/src/ob_cdc_multi_data_source_info.h @@ -53,7 +53,8 @@ public: inline bool is_tablet_change_node() const { return transaction::ObTxDataSourceType::CREATE_TABLET_NEW_MDS == tx_buf_node_.get_data_source_type() - || transaction::ObTxDataSourceType::DELETE_TABLET_NEW_MDS == tx_buf_node_.get_data_source_type(); + || transaction::ObTxDataSourceType::DELETE_TABLET_NEW_MDS == tx_buf_node_.get_data_source_type() + || transaction::ObTxDataSourceType::CHANGE_TABLET_TO_TABLE_MDS == tx_buf_node_.get_data_source_type(); } inline bool is_ddl_trans_node() const diff --git a/src/logservice/libobcdc/src/ob_cdc_tablet_to_table_info.cpp b/src/logservice/libobcdc/src/ob_cdc_tablet_to_table_info.cpp index f1be4f9ae..86ad3cbd8 100644 --- a/src/logservice/libobcdc/src/ob_cdc_tablet_to_table_info.cpp +++ b/src/logservice/libobcdc/src/ob_cdc_tablet_to_table_info.cpp @@ -15,7 +15,8 @@ #define USING_LOG_PREFIX OBLOG_PARSER #include "ob_cdc_tablet_to_table_info.h" - +#include "ob_log_hbase_mode.h" +#include "rootserver/ob_partition_exchange.h" #include "share/ob_errno.h" namespace oceanbase @@ -55,8 +56,33 @@ bool DeleteTabletOp::is_valid() const return tablet_id_.is_valid(); } +void ExchangeTabletOp::reset() +{ + tablet_ids_.reset(); + table_ids_.reset(); +} + +bool ExchangeTabletOp::is_valid() const +{ + return !tablet_ids_.empty() && !table_ids_.empty(); +} + +int ExchangeTabletOp::push_back_tablet_to_table(const common::ObTabletID &tablet_id, const uint64_t table_id) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(tablet_ids_.push_back(tablet_id))) { + LOG_ERROR("tablet_ids push_back fail", KR(ret), K_(tablet_ids), "count", tablet_ids_.count()); + } else if (OB_FAIL(table_ids_.push_back(table_id))) { + LOG_ERROR("table_ids push_back fail", KR(ret), K_(table_ids), "count", table_ids_.count()); + } else { + // succ + } + + return ret; +} + ObCDCTabletChangeInfo::ObCDCTabletChangeInfo() : - cmd_(TabletChangeCmd::CMD_UNKNOWN), create_tablet_op_arr_(), delete_tablet_op_arr_() + cmd_(TabletChangeCmd::CMD_UNKNOWN), create_tablet_op_arr_(), delete_tablet_op_arr_(), exchange_tablet_op_arr_() {} void ObCDCTabletChangeInfo::reset() @@ -64,6 +90,7 @@ void ObCDCTabletChangeInfo::reset() cmd_ = TabletChangeCmd::CMD_MAX; create_tablet_op_arr_.reset(); delete_tablet_op_arr_.reset(); + exchange_tablet_op_arr_.reset(); } void ObCDCTabletChangeInfo::reset(const TabletChangeCmd cmd) @@ -112,6 +139,19 @@ int ObCDCTabletChangeInfo::parse_from_multi_data_source_buf( } break; } + case transaction::ObTxDataSourceType::CHANGE_TABLET_TO_TABLE_MDS: + { + rootserver::ObChangeTabletToTableArg exchange_tablet_arg; + + if (OB_FAIL(exchange_tablet_arg.deserialize(buf, buf_len, pos))) { + LOG_ERROR("deserialize exchange_tablet_arg failed", KR(ret), K(tls_id), K(multi_data_source_node), + K(exchange_tablet_arg), K(buf_len), K(pos)); + } else if (OB_FAIL(parse_exchange_tablet_op_(tls_id, exchange_tablet_arg))) { + LOG_ERROR("parse_exchange_tablet_op_ failed", KR(ret), K(tls_id), K(multi_data_source_node), + K(exchange_tablet_arg), KPC(this)); + } + break; + } default: { ret = OB_NOT_SUPPORTED; @@ -219,6 +259,42 @@ int ObCDCTabletChangeInfo::parse_remove_tablet_op_( return ret; } +int ObCDCTabletChangeInfo::parse_exchange_tablet_op_( + const logservice::TenantLSID &tls_id, + const rootserver::ObChangeTabletToTableArg &exchange_tablet_arg) +{ + int ret = OB_SUCCESS; + cmd_ = TabletChangeCmd::CMD_EXCHANGE; + + if (OB_UNLIKELY(! exchange_tablet_arg.is_valid()) + || OB_UNLIKELY(tls_id.get_ls_id() != exchange_tablet_arg.ls_id_)) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("ObChangeTabletToTableArg is invalid", KR(ret), K(tls_id), K(exchange_tablet_arg)); + } else { + const common::ObSArray &tablet_ids = exchange_tablet_arg.tablet_ids_; + const common::ObSArray &table_ids = exchange_tablet_arg.table_ids_; + ExchangeTabletOp exchange_tablet_op; + + ARRAY_FOREACH_N(tablet_ids, tablet_id_idx, count) { + const common::ObTabletID &tablet_id = tablet_ids.at(tablet_id_idx); + const uint64_t table_id = table_ids.at(tablet_id_idx); + if (OB_FAIL(exchange_tablet_op.push_back_tablet_to_table(tablet_id, table_id))) { + LOG_ERROR("exchange_tablet_op push back failed", KR(ret), K(tablet_id), K(table_id)); + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(push_exchange_tablet_op_(exchange_tablet_op))) { + LOG_ERROR("push_exchange_tablet_op failed", KR(ret), K(tls_id), K(exchange_tablet_op), KPC(this)); + } else { + LOG_DEBUG("[EXCHANGE_TABLET_INFO]", K(tls_id), K(exchange_tablet_op)); + } + } + } + + return ret; +} + int ObCDCTabletChangeInfo::push_create_tablet_op_(const CreateTabletOp &create_tablet_op) { int ret = OB_SUCCESS; @@ -253,12 +329,31 @@ int ObCDCTabletChangeInfo::push_delete_tablet_op_(const DeleteTabletOp &delete_t return ret; } +int ObCDCTabletChangeInfo::push_exchange_tablet_op_(const ExchangeTabletOp &exchange_tablet_op) +{ + int ret = OB_SUCCESS; + + if (OB_UNLIKELY(!exchange_tablet_op.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_ERROR("invalid arg for push_exchange_tablet_op", KR(ret), K(exchange_tablet_op)); + } else if (OB_FAIL(exchange_tablet_op_arr_.push_back(exchange_tablet_op))) { + LOG_ERROR("push_exchange_tablet_op into exchange_tablet_op_arr_ failed", + KR(ret), K(exchange_tablet_op), K_(exchange_tablet_op_arr)); + } else { + // success + } + + return ret; +} + void ObCDCTabletChangeInfo::print_detail_for_debug() const { if (is_create_tablet_op()) { LOG_DEBUG("tablet_change_info", "create_cnt", create_tablet_op_arr_.count(), K_(create_tablet_op_arr)); } else if (is_delete_tablet_op()) { LOG_DEBUG("tablet_change_info", "delete_cnt", delete_tablet_op_arr_.count(), K_(delete_tablet_op_arr)); + } else if (is_exchange_tablet_op()) { + LOG_DEBUG("tablet_change_info", K_(exchange_tablet_op_arr)); } else { LOG_DEBUG("tablet_change_info: None"); } @@ -360,6 +455,46 @@ int TabletToTableInfo::insert_tablet_table_info(const common::ObTabletID &tablet return ret; } +int TabletToTableInfo::exchange_tablet_table_info(const common::ObSArray &tablet_ids, const common::ObSArray &table_ids) +{ + int ret = OB_SUCCESS; + common::ObLinearHashMap table_to_table_info_map; + + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_ERROR("TabletIDToTableIDInfo is not inited", KR(ret), K_(is_inited)); + } else if (OB_FAIL(table_to_table_info_map.init("TableToTable"))) { + LOG_ERROR("table_to_table_info_map init failed", KR(ret)); + } else { + ARRAY_FOREACH_N(tablet_ids, idx, count) { + const common::ObTabletID &tablet_id = tablet_ids.at(idx); + ObCDCTableInfo tmp_table_info; + if (OB_FAIL(tablet_to_table_map_.get(tablet_id, tmp_table_info))) { + LOG_ERROR("tablet_to_table_map_ get failed", KR(ret), K(tablet_id)); + } else if (OB_FAIL(table_to_table_info_map.insert(TableID(tmp_table_info.get_table_id()), tmp_table_info))) { + LOG_ERROR("table_to_table_info_map insert failed", KR(ret), K(tablet_id), K(tmp_table_info)); + } else { + LOG_INFO("table_to_table_info_map insert success", K(tablet_id), K(tmp_table_info)); + } + } + + ARRAY_FOREACH_N(tablet_ids, idx, count) { + const common::ObTabletID &tablet_id = tablet_ids.at(idx); + const uint64_t table_id = table_ids.at(idx); + ObCDCTableInfo tmp_table_info; + if (OB_FAIL(table_to_table_info_map.get(TableID(table_id), tmp_table_info))) { + LOG_ERROR("table_to_table_info_map get failed", KR(ret), K(table_id)); + } else if (OB_FAIL(tablet_to_table_map_.insert_or_update(tablet_id, tmp_table_info))) { + LOG_ERROR("tablet_to_table_map_ update failed", KR(ret), K(tablet_id), K(tmp_table_info)); + } else { + LOG_INFO("tablet_to_table_map_ update success", K(tablet_id), K(table_id), K(tmp_table_info)); + } + } + } + + return ret; +} + int TabletToTableInfo::remove_tablet_table_info(const common::ObTabletID &tablet_id) { int ret = OB_SUCCESS; diff --git a/src/logservice/libobcdc/src/ob_cdc_tablet_to_table_info.h b/src/logservice/libobcdc/src/ob_cdc_tablet_to_table_info.h index ff84328db..21be67435 100644 --- a/src/logservice/libobcdc/src/ob_cdc_tablet_to_table_info.h +++ b/src/logservice/libobcdc/src/ob_cdc_tablet_to_table_info.h @@ -21,11 +21,16 @@ #include "storage/tx/ob_multi_data_source.h" // ObTxBufferNode #include "rootserver/ob_tablet_creator.h" // ObBatchCreateTabletArg #include "rootserver/ob_tablet_drop.h" // ObBatchRemoveTabletArg - #include "logservice/common_util/ob_log_ls_define.h" namespace oceanbase { + +namespace rootserver +{ + class ObChangeTabletToTableArg; +} + namespace libobcdc { // TabletChangeOp Type @@ -35,6 +40,7 @@ enum TabletChangeCmd CMD_CREATE, CMD_DELETE, CMD_TRANSFER, + CMD_EXCHANGE, CMD_MAX }; @@ -118,6 +124,30 @@ private: common::ObTabletID tablet_id_; }; +// data used for ExchangeTablet +class ExchangeTabletOp +{ +public: + ExchangeTabletOp() { reset(); } + ~ExchangeTabletOp() { reset(); } + void reset(); +public: + bool is_valid() const; + int push_back_tablet_to_table(const common::ObTabletID &tablet_id, const uint64_t table_id); + const common::ObSArray &get_tablet_ids() const { return tablet_ids_; } + const common::ObSArray &get_table_ids() const { return table_ids_; } +public: + TO_STRING_KV( + K_(tablet_ids), + "tablet_ids_count", tablet_ids_.count(), + K_(table_ids), + "table_id_count", table_ids_.count()); +private: + // use array to also store related table, such as lob aux table + common::ObSArray tablet_ids_; + common::ObSArray table_ids_; +}; + // struct store the TabletChangeOp that get from LS_MEMTABLE mulit_data_source trans class ObCDCTabletChangeInfo { @@ -133,18 +163,22 @@ public: public: inline bool is_valid() const { - return (TabletChangeCmd::CMD_CREATE == cmd_ && 0 >= delete_tablet_op_arr_.count()) // create_tablet_op_arr_ may empty after filter tablet. - || (TabletChangeCmd::CMD_DELETE == cmd_ && 0 >= create_tablet_op_arr_.count()); // delete_tablet_op_arri_ may empty. + return (TabletChangeCmd::CMD_CREATE == cmd_ && 0 >= delete_tablet_op_arr_.count() && 0 >= exchange_tablet_op_arr_.count()) // create_tablet_op_arr_ may empty after filter tablet. + || (TabletChangeCmd::CMD_DELETE == cmd_ && 0 >= create_tablet_op_arr_.count() && 0 >= exchange_tablet_op_arr_.count()) // delete_tablet_op_arr_ may empty. + || (TabletChangeCmd::CMD_EXCHANGE == cmd_ && 0 >= create_tablet_op_arr_.count() && 0 >= delete_tablet_op_arr_.count()); // exchange_tablet_op_arr_ may empty. } inline bool is_create_tablet_op() const { return TabletChangeCmd::CMD_CREATE == cmd_; } inline bool is_delete_tablet_op() const { return TabletChangeCmd::CMD_DELETE == cmd_; } - const ObArray &get_create_tablet_op_arr() const { return create_tablet_op_arr_; } - const ObArray &get_delete_tablet_op_arr() const { return delete_tablet_op_arr_; } + inline bool is_exchange_tablet_op() const { return TabletChangeCmd::CMD_EXCHANGE == cmd_; } + const ObArray &get_create_tablet_op_arr() const { return create_tablet_op_arr_; } + const ObArray &get_delete_tablet_op_arr() const { return delete_tablet_op_arr_; } + const ObArray &get_exchange_tablet_op_arr() const { return exchange_tablet_op_arr_; } public: void print_detail_for_debug() const; TO_STRING_KV(K_(cmd), - "create_tablet_cnt", create_tablet_op_arr_.count(), - "delete_tablet_cnt", delete_tablet_op_arr_.count()); + "create_tablet_cnt", create_tablet_op_arr_.count(), + "delete_tablet_cnt", delete_tablet_op_arr_.count(), + "exchange_tablet_cnt", exchange_tablet_op_arr_.count()); private: int parse_create_tablet_op_( const logservice::TenantLSID &tls_id, @@ -152,12 +186,17 @@ private: int parse_remove_tablet_op_( const logservice::TenantLSID &tls_id, const obrpc::ObBatchRemoveTabletArg &remove_tablet_arg); + int parse_exchange_tablet_op_( + const logservice::TenantLSID &tls_id, + const rootserver::ObChangeTabletToTableArg &exchange_tablet_arg); int push_create_tablet_op_(const CreateTabletOp &create_tablet_op); int push_delete_tablet_op_(const DeleteTabletOp &delete_tablet_op); + int push_exchange_tablet_op_(const ExchangeTabletOp &exchange_tablet_op); private: TabletChangeCmd cmd_; - ObArray create_tablet_op_arr_; - ObArray delete_tablet_op_arr_; + ObArray create_tablet_op_arr_; + ObArray delete_tablet_op_arr_; + ObArray exchange_tablet_op_arr_; }; typedef common::ObLinearHashMap TabletToTableMap; // Map of TabletID->TableID @@ -196,6 +235,17 @@ public: /// @retval other ERROR unexpected error. int insert_tablet_table_info(const common::ObTabletID &tablet_id, const ObCDCTableInfo &table_info); + /// exchange tablet_id->table_info + /// + /// @param [in] tablet_id tablet_id to insert + /// @param [in] table_info table_info of tablet_id + /// + /// @retval OB_SUCCESS replace success + /// @retval OB_INVALID_ARGUMENT tablet_id is invalid + /// @retval OB_ENTRY_NOT_EXIST the tablet_id is not in tablet_to_table_map_ + /// @retval other ERROR unexpected error + int exchange_tablet_table_info(const common::ObSArray &tablet_ids, const common::ObSArray &table_ids); + /// remove tablet_id->table_info pair for specified tablet_id /// /// @param [in] tablet_id tablet_id to remove diff --git a/src/logservice/libobcdc/src/ob_log_part_mgr.cpp b/src/logservice/libobcdc/src/ob_log_part_mgr.cpp index 49e7fd84a..cbe14e07e 100644 --- a/src/logservice/libobcdc/src/ob_log_part_mgr.cpp +++ b/src/logservice/libobcdc/src/ob_log_part_mgr.cpp @@ -1345,6 +1345,38 @@ int ObLogPartMgr::apply_delete_tablet_change(const ObCDCTabletChangeInfo &tablet return ret; } +int ObLogPartMgr::apply_exchange_tablet_change(const ObCDCTabletChangeInfo &tablet_change_info) +{ + int ret = OB_SUCCESS; + + if (OB_UNLIKELY(! tablet_change_info.is_valid()) + || OB_UNLIKELY(! tablet_change_info.is_exchange_tablet_op())) { + ret = OB_INVALID_ARGUMENT; + LOG_ERROR("invalid tablet_change_info for exchange_tablet_op", KR(ret), K(tablet_change_info)); + } else { + const ObArray &exchange_tablet_op_arr = tablet_change_info.get_exchange_tablet_op_arr(); + + ARRAY_FOREACH_N(exchange_tablet_op_arr, idx, count) { + const ExchangeTabletOp &exchange_tablet_op = exchange_tablet_op_arr.at(idx); + if (OB_UNLIKELY(! exchange_tablet_op.is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("exchange_tablet_op is invalid", KR(ret), K(exchange_tablet_op)); + } else { + const common::ObSArray &tablet_ids = exchange_tablet_op.get_tablet_ids(); + const common::ObSArray &table_ids = exchange_tablet_op.get_table_ids(); + + if (OB_FAIL(tablet_to_table_info_.exchange_tablet_table_info(tablet_ids, table_ids))) { + LOG_ERROR("tablet_to_table_info_ exchange table info failed", K(tablet_ids), K(table_ids)); + } else { + LOG_INFO("apply_exchange_tablet_change success", K(tablet_ids), K(table_ids)); + } + } + } + } + + return ret; +} + // @retval OB_SUCCESS success // @retval OB_TIMEOUT timeout // @retval OB_TENANT_HAS_BEEN_DROPPED caller should ignore error code if schema error like tenant/database not exist diff --git a/src/logservice/libobcdc/src/ob_log_part_mgr.h b/src/logservice/libobcdc/src/ob_log_part_mgr.h index ec4ed278e..9d38d48d6 100644 --- a/src/logservice/libobcdc/src/ob_log_part_mgr.h +++ b/src/logservice/libobcdc/src/ob_log_part_mgr.h @@ -257,6 +257,7 @@ public: virtual int insert_table_id_into_cache(const uint64_t table_id, const uint64_t database_id) = 0; virtual int delete_table_id_from_cache(const uint64_t table_id) = 0; virtual int delete_db_from_cache(const uint64_t database_id) = 0; + virtual int apply_exchange_tablet_change(const ObCDCTabletChangeInfo &tablet_change_info) = 0; }; ///////////////////////////////////////////////////////////////////////////// @@ -368,6 +369,7 @@ public: virtual int insert_table_id_into_cache(const uint64_t table_id, const uint64_t database_id); virtual int delete_table_id_from_cache(const uint64_t table_id); virtual int delete_db_from_cache(const uint64_t database_id); + virtual int apply_exchange_tablet_change(const ObCDCTabletChangeInfo &tablet_change_info); private: template diff --git a/src/logservice/libobcdc/src/ob_log_part_trans_task.cpp b/src/logservice/libobcdc/src/ob_log_part_trans_task.cpp index a543749e3..ee225ed79 100644 --- a/src/logservice/libobcdc/src/ob_log_part_trans_task.cpp +++ b/src/logservice/libobcdc/src/ob_log_part_trans_task.cpp @@ -2576,6 +2576,7 @@ int PartTransTask::push_multi_data_source_data( } case transaction::ObTxDataSourceType::CREATE_TABLET_NEW_MDS: case transaction::ObTxDataSourceType::DELETE_TABLET_NEW_MDS: + case transaction::ObTxDataSourceType::CHANGE_TABLET_TO_TABLE_MDS: { if (! is_commit_log) { if (OB_FAIL(alloc_and_save_multi_data_source_node_(lsn, mds_buffer_node))) { diff --git a/src/logservice/libobcdc/src/ob_log_sequencer1.cpp b/src/logservice/libobcdc/src/ob_log_sequencer1.cpp index 76d571a8f..8ad9620db 100644 --- a/src/logservice/libobcdc/src/ob_log_sequencer1.cpp +++ b/src/logservice/libobcdc/src/ob_log_sequencer1.cpp @@ -1030,6 +1030,16 @@ int ObLogSequencer::handle_multi_data_source_info_( } else { LOG_DEBUG("CDC_DELETE_TABLET", KR(ret), K(tablet_change_info), K(part_trans_task), KPC(part_trans_task), K(tenant)); } + } else if (tablet_change_info.is_exchange_tablet_op()) { + if (OB_FAIL(wait_until_parser_done_("exchange_tablet_op", stop_flag))) { + if (OB_IN_STOP_STATE != ret) { + LOG_ERROR("wait_until_parser_done_ failed", KR(ret), KPC(part_trans_task)); + } + } else if (OB_FAIL(part_mgr.apply_exchange_tablet_change(tablet_change_info))) { + LOG_ERROR("apply_exchange_tablet_change failed", KR(ret), K(tablet_change_info), K(tenant), KPC(part_trans_task)); + } else { + LOG_INFO("CDC_EXCHANGE_TABLET", KR(ret), K(tablet_change_info), K(part_trans_task), KPC(part_trans_task), K(tenant)); + } } } } diff --git a/src/objit/include/objit/common/ob_item_type.h b/src/objit/include/objit/common/ob_item_type.h index 92fc80abe..154276d26 100755 --- a/src/objit/include/objit/common/ob_item_type.h +++ b/src/objit/include/objit/common/ob_item_type.h @@ -2428,14 +2428,12 @@ typedef enum ObItemType T_SHOW_FUNCTION_CODE, T_CHANGE_EXTERNAL_STORAGE_DEST, T_ALTER_USER_PROXY, - T_PARALLEL_DAS_DML, T_DISABLE_PARALLEL_DAS_DML, T_ENABLE_LOB_PREFETCH, T_MV_OPTIONS, T_MV_REWRITE, T_MV_NO_REWRITE, - // select into outfile T_INTO_FILE_LIST, T_SINGLE_OPT, diff --git a/src/observer/ob_srv_xlator_rootserver.cpp b/src/observer/ob_srv_xlator_rootserver.cpp index 506de874f..9842b6d27 100644 --- a/src/observer/ob_srv_xlator_rootserver.cpp +++ b/src/observer/ob_srv_xlator_rootserver.cpp @@ -106,6 +106,7 @@ void oceanbase::observer::init_srv_xlator_for_rootserver(ObSrvRpcXlator *xlator) RPC_PROCESSOR(rootserver::ObRpcUpdateDDLTaskActiveTimeP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcCreateHiddenTableP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcAlterTableP, *gctx_.root_service_); + RPC_PROCESSOR(rootserver::ObRpcExchangePartitionP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcDropTableP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcRenameTableP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcTruncateTableP, *gctx_.root_service_); diff --git a/src/rootserver/CMakeLists.txt b/src/rootserver/CMakeLists.txt index 37afb4bb5..ccc555b71 100644 --- a/src/rootserver/CMakeLists.txt +++ b/src/rootserver/CMakeLists.txt @@ -101,6 +101,7 @@ ob_set_subtarget(ob_rootserver common ob_ls_recovery_stat_handler.cpp ob_shrink_expand_resource_pool_checker.cpp ob_transfer_partition_command.cpp + ob_partition_exchange.cpp ) ob_set_subtarget(ob_rootserver balance diff --git a/src/rootserver/ob_ddl_operator.cpp b/src/rootserver/ob_ddl_operator.cpp index 3aa7f42cc..9972e793a 100644 --- a/src/rootserver/ob_ddl_operator.cpp +++ b/src/rootserver/ob_ddl_operator.cpp @@ -12022,6 +12022,183 @@ int ObDDLOperator::try_add_dep_info_for_synonym(const ObSimpleSynonymSchema *syn return ret; } +int ObDDLOperator::exchange_table_partitions(const share::schema::ObTableSchema &orig_table_schema, + share::schema::ObTableSchema &inc_table_schema, + share::schema::ObTableSchema &del_table_schema, + common::ObMySQLTransaction &trans) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = orig_table_schema.get_tenant_id(); + int64_t new_schema_version = OB_INVALID_VERSION; + ObSchemaService *schema_service = schema_service_.get_schema_service(); + if (OB_ISNULL(schema_service)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("schema_service is NULL", K(ret)); + } else if (OB_FAIL(schema_service_.gen_new_schema_version(tenant_id, new_schema_version))) { + LOG_WARN("fail to gen new schema_version", K(ret), K(tenant_id)); + } else if (OB_FAIL(schema_service->get_table_sql_service().exchange_part_info( + trans, + orig_table_schema, + inc_table_schema, + del_table_schema, + new_schema_version))) { + LOG_WARN("exchange part info failed", K(ret)); + } + return ret; +} + +int ObDDLOperator::exchange_table_subpartitions(const share::schema::ObTableSchema &orig_table_schema, + share::schema::ObTableSchema &inc_table_schema, + share::schema::ObTableSchema &del_table_schema, + common::ObMySQLTransaction &trans) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = orig_table_schema.get_tenant_id(); + int64_t new_schema_version = OB_INVALID_VERSION; + ObSchemaService *schema_service = schema_service_.get_schema_service(); + if (OB_ISNULL(schema_service)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("schema_service is NULL", K(ret)); + } else if (OB_FAIL(schema_service_.gen_new_schema_version(tenant_id, new_schema_version))) { + LOG_WARN("fail to gen new schema_version", K(ret), K(tenant_id)); + } else if (OB_FAIL(schema_service->get_table_sql_service().exchange_subpart_info( + trans, + orig_table_schema, + inc_table_schema, + del_table_schema, + new_schema_version))) { + LOG_WARN("delete inc part info failed", K(ret)); + } + return ret; +} + +int ObDDLOperator::get_target_auto_inc_sequence_value(const uint64_t tenant_id, + const uint64_t table_id, + const uint64_t column_id, + uint64_t &sequence_value, + common::ObMySQLTransaction &trans) +{ + int ret = OB_SUCCESS; + sequence_value = OB_INVALID_ID; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == table_id || OB_INVALID_ID == column_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(table_id), K(column_id)); + } else { + ObSqlString sql; + const uint64_t exec_tenant_id = tenant_id; + const char *table_name = OB_ALL_AUTO_INCREMENT_TNAME; + if (OB_FAIL(sql.assign_fmt(" SELECT sequence_value FROM %s WHERE tenant_id = %lu AND sequence_key = %lu" + " AND column_id = %lu FOR UPDATE", + table_name, + ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id), + ObSchemaUtils::get_extract_schema_id(exec_tenant_id, table_id), + column_id))) { + LOG_WARN("failed to assign sql", K(ret), K(tenant_id), K(table_id), K(column_id)); + } else { + SMART_VAR(ObMySQLProxy::MySQLResult, res) { + ObMySQLResult *result = NULL; + uint64_t sequence_table_id = OB_ALL_AUTO_INCREMENT_TID; + if (OB_FAIL(trans.read(res, exec_tenant_id, sql.ptr()))) { + LOG_WARN("failed to read data", K(ret)); + } else if (NULL == (result = res.get_result())) { + LOG_WARN("failed to get result", K(ret)); + ret = OB_ERR_UNEXPECTED; + } else if (OB_FAIL(result->next())) { + LOG_WARN("failed to get next", K(ret)); + if (OB_ITER_END == ret) { + // auto-increment column has been deleted + ret = OB_SCHEMA_ERROR; + LOG_WARN("failed to get next", K(ret)); + } + } else if (OB_FAIL(result->get_uint("sequence_value", sequence_value))) { + LOG_WARN("failed to get int_value.", K(ret)); + } + if (OB_SUCC(ret)) { + int tmp_ret = OB_SUCCESS; + if (OB_ITER_END != (tmp_ret = result->next())) { + if (OB_SUCCESS == tmp_ret) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("more than one row", K(ret), K(tenant_id), K(table_id), K(column_id)); + } else { + ret = tmp_ret; + LOG_WARN("fail to iter next row", K(ret), K(tenant_id), K(table_id), K(column_id)); + } + } + } + } + } + } + return ret; +} + +int ObDDLOperator::set_target_auto_inc_sync_value(const uint64_t tenant_id, + const uint64_t table_id, + const uint64_t column_id, + const uint64_t new_sequence_value, + const uint64_t new_sync_value, + common::ObMySQLTransaction &trans) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == table_id || OB_INVALID_ID == column_id || new_sequence_value < 0 || new_sync_value < 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(table_id), K(column_id), K(new_sequence_value), K(new_sync_value)); + } else { + ObSqlString sql; + int64_t affected_rows = 0; + const char *table_name = OB_ALL_AUTO_INCREMENT_TNAME; + if (OB_FAIL(sql.assign_fmt( + "UPDATE %s SET sequence_value = %lu, sync_value = %lu WHERE tenant_id=%lu AND sequence_key=%lu AND column_id=%lu", + table_name, new_sequence_value, new_sync_value, + ObSchemaUtils::get_extract_tenant_id(tenant_id, tenant_id), ObSchemaUtils::get_extract_schema_id(tenant_id, table_id), column_id))) { + LOG_WARN("failed to assign sql", K(ret), K(tenant_id), K(table_id), K(column_id), K(new_sequence_value), K(new_sync_value)); + } else if (OB_FAIL(trans.write(tenant_id, sql.ptr(), affected_rows))) { + LOG_WARN("failed to execute", K(ret), K(sql)); + } + } + return ret; +} + +int ObDDLOperator::get_target_sequence_sync_value(const uint64_t tenant_id, + const uint64_t sequence_id, + common::ObMySQLTransaction &trans, + ObIAllocator &allocator, + common::number::ObNumber &next_value) +{ + int ret = OB_SUCCESS; + next_value.set_zero(); + ObSchemaService *schema_service_impl = schema_service_.get_schema_service(); + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == sequence_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(sequence_id)); + } else if (OB_ISNULL(schema_service_impl)) { + ret = OB_ERR_SYS; + LOG_ERROR("schema_service_impl must not null", K(ret)); + } else if (OB_FAIL(schema_service_impl->get_sequence_sql_service().get_sequence_sync_value(tenant_id, + sequence_id, + true,/*is select for update*/ + trans, + allocator, + next_value))) { + LOG_WARN("fail to get sequence sync value", K(ret), K(tenant_id), K(sequence_id)); + } + return ret; +} + +int ObDDLOperator::alter_target_sequence_start_with(const ObSequenceSchema &sequence_schema, common::ObMySQLTransaction &trans) +{ + int ret = OB_SUCCESS; + ObSchemaService *schema_service_impl = schema_service_.get_schema_service(); + if (OB_UNLIKELY(!sequence_schema.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(sequence_schema)); + } else if (OB_ISNULL(schema_service_impl)) { + ret = OB_ERR_SYS; + LOG_ERROR("schema_service_impl must not null", K(ret)); + } else if (OB_FAIL(schema_service_impl->get_sequence_sql_service().alter_sequence_start_with(sequence_schema, trans))) { + LOG_WARN("fail to alter sequence start with", K(ret), K(sequence_schema)); + } + return ret; +} }//end namespace rootserver }//end namespace oceanbase diff --git a/src/rootserver/ob_ddl_operator.h b/src/rootserver/ob_ddl_operator.h index 07ecd8beb..b2ca522c3 100644 --- a/src/rootserver/ob_ddl_operator.h +++ b/src/rootserver/ob_ddl_operator.h @@ -1023,6 +1023,32 @@ public: const share::schema::ObTableSchema *table); int try_add_dep_info_for_synonym(const ObSimpleSynonymSchema *synonym_info, common::ObMySQLTransaction &trans); + int exchange_table_partitions(const share::schema::ObTableSchema &orig_table_schema, + share::schema::ObTableSchema &inc_table_schema, + share::schema::ObTableSchema &del_table_schema, + common::ObMySQLTransaction &trans); + int exchange_table_subpartitions(const share::schema::ObTableSchema &orig_table_schema, + share::schema::ObTableSchema &inc_table_schema, + share::schema::ObTableSchema &del_table_schema, + common::ObMySQLTransaction &trans); + int get_target_auto_inc_sequence_value(const uint64_t tenant_id, + const uint64_t table_id, + const uint64_t column_id, + uint64_t &sequence_value, + common::ObMySQLTransaction &trans); + int set_target_auto_inc_sync_value(const uint64_t tenant_id, + const uint64_t table_id, + const uint64_t column_id, + const uint64_t new_sequence_value, + const uint64_t new_sync_value, + common::ObMySQLTransaction &trans); + int get_target_sequence_sync_value(const uint64_t tenant_id, + const uint64_t sequence_id, + common::ObMySQLTransaction &trans, + ObIAllocator &allocator, + common::number::ObNumber &next_value); + int alter_target_sequence_start_with(const ObSequenceSchema &sequence_schema, + common::ObMySQLTransaction &trans); private: virtual int set_need_flush_ora( share::schema::ObSchemaGetterGuard &schema_guard, diff --git a/src/rootserver/ob_ddl_service.cpp b/src/rootserver/ob_ddl_service.cpp index f8744dd51..016d3bf07 100755 --- a/src/rootserver/ob_ddl_service.cpp +++ b/src/rootserver/ob_ddl_service.cpp @@ -38648,8 +38648,8 @@ int ObDDLService::check_rename_first(const AlterTableSchema &alter_table_schema, } int ObDDLService::fix_local_idx_part_name_(const ObSimpleTableSchemaV2 &ori_data_table_schema, - const ObSimpleTableSchemaV2 &ori_table_schema, - ObSimpleTableSchemaV2 &inc_table_schema) + const ObSimpleTableSchemaV2 &ori_table_schema, + ObSimpleTableSchemaV2 &inc_table_schema) { int ret = OB_SUCCESS; bool ori_oracle_mode = false; @@ -38701,7 +38701,7 @@ int ObDDLService::fix_local_idx_part_name_(const ObSimpleTableSchemaV2 &ori_data ret = OB_ERR_UNEXPECTED; LOG_WARN("src part is null", KR(ret)); } else if (FALSE_IT(part_name = ori_part->get_part_name())){ - } else if (OB_FAIL(check_same_partition_(ori_oracle_mode, *ori_data_part, *ori_part, ori_part_func_type, is_matched))) { + } else if (OB_FAIL(check_same_partition(ori_oracle_mode, *ori_data_part, *ori_part, ori_part_func_type, is_matched))) { LOG_WARN("fail to check ori_table_part and ori_aux_part is the same", KR(ret), KPC(ori_data_part), KPC(ori_part), K(ori_part_func_type)); } else if (OB_UNLIKELY(!is_matched)) { ret = OB_INDEX_INELIGIBLE; @@ -38716,8 +38716,8 @@ int ObDDLService::fix_local_idx_part_name_(const ObSimpleTableSchemaV2 &ori_data } int ObDDLService::fix_local_idx_subpart_name_(const ObSimpleTableSchemaV2 &ori_data_table_schema, - const ObSimpleTableSchemaV2 &ori_table_schema, - ObSimpleTableSchemaV2 &inc_table_schema) + const ObSimpleTableSchemaV2 &ori_table_schema, + ObSimpleTableSchemaV2 &inc_table_schema) { int ret = OB_SUCCESS; bool ori_oracle_mode = false; @@ -38782,7 +38782,7 @@ int ObDDLService::fix_local_idx_subpart_name_(const ObSimpleTableSchemaV2 &ori_d } else if (OB_ISNULL(ori_part)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("src part is null", KR(ret)); - } else if (OB_FAIL(check_same_partition_(ori_oracle_mode, *ori_data_part, *ori_part, ori_part_func_type, is_matched))) { + } else if (OB_FAIL(check_same_partition(ori_oracle_mode, *ori_data_part, *ori_part, ori_part_func_type, is_matched))) { LOG_WARN("fail to check ori_table_part and ori_aux_part is the same", KR(ret), KPC(ori_data_part), KPC(ori_part), K(ori_part_func_type)); } else if (OB_UNLIKELY(!is_matched)) { ret = OB_INDEX_INELIGIBLE; @@ -38796,7 +38796,7 @@ int ObDDLService::fix_local_idx_subpart_name_(const ObSimpleTableSchemaV2 &ori_d ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get src subpart.", KR(ret)); } else if (FALSE_IT(part_name = ori_subpart->get_part_name())) { - } else if (OB_FAIL(check_same_subpartition_(ori_oracle_mode, *ori_data_subpart, *ori_subpart, ori_subpart_func_type, is_matched))) { + } else if (OB_FAIL(check_same_subpartition(ori_oracle_mode, *ori_data_subpart, *ori_subpart, ori_subpart_func_type, is_matched))) { LOG_WARN("fail to check ori_table_subpart and ori_aux_subpart is the same", KR(ret), KPC(ori_data_part), KPC(ori_part), K(ori_subpart_func_type)); } else if (OB_UNLIKELY(!is_matched)) { ret = OB_INDEX_INELIGIBLE; @@ -38912,7 +38912,7 @@ int ObDDLService::fix_local_idx_part_name_for_add_subpart_(const ObSimpleTableSc return ret; } -int ObDDLService::check_same_partition_(const bool is_oracle_mode, const ObPartition &l, const ObPartition &r, +int ObDDLService::check_same_partition(const bool is_oracle_mode, const ObPartition &l, const ObPartition &r, const ObPartitionFuncType part_type, bool &is_matched) const { int ret = OB_SUCCESS; @@ -38931,7 +38931,7 @@ int ObDDLService::check_same_partition_(const bool is_oracle_mode, const ObParti return ret; } -int ObDDLService::check_same_subpartition_(const bool is_oracle_mode, const ObSubPartition &l, const ObSubPartition &r, +int ObDDLService::check_same_subpartition(const bool is_oracle_mode, const ObSubPartition &l, const ObSubPartition &r, const ObPartitionFuncType part_type, bool &is_matched) const { int ret = OB_SUCCESS; diff --git a/src/rootserver/ob_ddl_service.h b/src/rootserver/ob_ddl_service.h index 00ce51fc7..a1b70da64 100644 --- a/src/rootserver/ob_ddl_service.h +++ b/src/rootserver/ob_ddl_service.h @@ -2576,9 +2576,43 @@ private: int gen_inc_table_schema_for_add_part( const share::schema::ObTableSchema &orig_table_schema, share::schema::AlterTableSchema &inc_table_schema); + int gen_inc_table_schema_for_add_subpart( + const share::schema::ObTableSchema &orig_table_schema, + share::schema::AlterTableSchema &inc_table_schema); int gen_inc_table_schema_for_drop_part( const share::schema::ObTableSchema &orig_table_schema, share::schema::AlterTableSchema &inc_table_schema); + int gen_inc_table_schema_for_drop_subpart( + const share::schema::ObTableSchema &orig_table_schema, + share::schema::AlterTableSchema &inc_table_schema); +public: + //not check belong to the same table + int check_same_partition(const bool is_oracle_mode, const ObPartition &l, const ObPartition &r, + const ObPartitionFuncType part_type, bool &is_matched) const; + //not check belong to the same table + int check_same_subpartition(const bool is_oracle_mode, const ObSubPartition &l, const ObSubPartition &r, + const ObPartitionFuncType part_type, bool &is_matched) const; +private: + //After renaming a partition/subpartition, the consistency of the partition name between the data table and aux table is no longer guaranteed. + //Therefore, the partition names in the inc aux table must be synchronized with the ori aux table after assigning the data table's partition + //schema to the inc aux table. + //This function relies on the assumption that the inc table schema has a valid partition name. + int fix_local_idx_part_name_(const ObSimpleTableSchemaV2 &ori_data_table_schema, + const ObSimpleTableSchemaV2 &ori_table_schema, + ObSimpleTableSchemaV2 &inc_table_schema); + //This function relies on the assumption that the inc table schema has a valid subpartition name. + int fix_local_idx_subpart_name_(const ObSimpleTableSchemaV2 &ori_data_table_schema, + const ObSimpleTableSchemaV2 &ori_table_schema, + ObSimpleTableSchemaV2 &inc_table_schema); + //During the process of adding a partition/subpartition, we only check whether the partition schema of the argument is valid. + //It's possible for the inc aux table's partition name to duplicate with an existing partition name if one renames a partition/subpartition + //to another name and then adds a partition/subpartition with the same name. + //In this case, we will generate a name with a part/subpart id to replace the inc part/subpart name to avoid duplication. + int fix_local_idx_part_name_for_add_part_(const ObSimpleTableSchemaV2 &ori_table_schema, + ObSimpleTableSchemaV2 &inc_table_schema); + + int fix_local_idx_part_name_for_add_subpart_(const ObSimpleTableSchemaV2 &ori_table_schema, + ObSimpleTableSchemaV2 &inc_table_schema); int gen_inc_table_schema_for_rename_part_( const share::schema::ObTableSchema &orig_table_schema, share::schema::AlterTableSchema &inc_table_schema); @@ -2586,12 +2620,6 @@ private: const share::schema::ObTableSchema &orig_table_schema, share::schema::AlterTableSchema &inc_table_schema, share::schema::AlterTableSchema &del_table_schema); - int gen_inc_table_schema_for_add_subpart( - const share::schema::ObTableSchema &orig_table_schema, - share::schema::AlterTableSchema &inc_table_schema); - int gen_inc_table_schema_for_drop_subpart( - const share::schema::ObTableSchema &orig_table_schema, - share::schema::AlterTableSchema &inc_table_schema); int gen_inc_table_schema_for_rename_subpart_( const share::schema::ObTableSchema &orig_table_schema, share::schema::AlterTableSchema &inc_table_schema); @@ -2637,34 +2665,6 @@ private: const share::schema::ObTenantSchema &orig_tenant_schema, const share::schema::ObTenantSchema &new_tenant_schema); - //not check belong to the same table - int check_same_partition_(const bool is_oracle_mode, const ObPartition &l, const ObPartition &r, - const ObPartitionFuncType part_type, bool &is_matched) const; - //not check belong to the same table - int check_same_subpartition_(const bool is_oracle_mode, const ObSubPartition &l, const ObSubPartition &r, - const ObPartitionFuncType part_type, bool &is_matched) const; - //After renaming a partition/subpartition, the consistency of the partition name between the data table and aux table is no longer guaranteed. - //Therefore, the partition names in the inc aux table must be synchronized with the ori aux table after assigning the data table's partition - //schema to the inc aux table. - //This function relies on the assumption that the inc table schema has a valid partition name. - int fix_local_idx_part_name_(const ObSimpleTableSchemaV2 &ori_data_table_schema, - const ObSimpleTableSchemaV2 &ori_table_schema, - ObSimpleTableSchemaV2 &inc_table_schema); - //This function relies on the assumption that the inc table schema has a valid subpartition name. - int fix_local_idx_subpart_name_(const ObSimpleTableSchemaV2 &ori_data_table_schema, - const ObSimpleTableSchemaV2 &ori_table_schema, - ObSimpleTableSchemaV2 &inc_table_schema); - //During the process of adding a partition/subpartition, we only check whether the partition schema of the argument is valid. - //It's possible for the inc aux table's partition name to duplicate with an existing partition name if one renames a partition/subpartition - //to another name and then adds a partition/subpartition with the same name. - //In this case, we will generate a name with a part/subpart id to replace the inc part/subpart name to avoid duplication. - int fix_local_idx_part_name_for_add_part_(const ObSimpleTableSchemaV2 &ori_table_schema, - ObSimpleTableSchemaV2 &inc_table_schema); - - int fix_local_idx_part_name_for_add_subpart_(const ObSimpleTableSchemaV2 &ori_table_schema, - ObSimpleTableSchemaV2 &inc_table_schema); - -private: int check_locality_compatible_(ObTenantSchema &schema); int pre_rename_mysql_columns_online(const ObTableSchema &origin_table_schema, diff --git a/src/rootserver/ob_partition_exchange.cpp b/src/rootserver/ob_partition_exchange.cpp new file mode 100644 index 000000000..3346b26b8 --- /dev/null +++ b/src/rootserver/ob_partition_exchange.cpp @@ -0,0 +1,2670 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX RS +#include "ob_partition_exchange.h" +#include "share/ob_define.h" +#include "lib/allocator/page_arena.h" +#include "lib/container/ob_array_iterator.h" +#include "lib/mysqlclient/ob_mysql_transaction.h" +#include "ob_ddl_service.h" +#include "ob_root_service.h" +#include "observer/ob_sql_client_decorator.h" // ObSQLClientRetryWeak +#include "share/ob_ddl_common.h" +#include "share/ob_debug_sync.h" +#include "share/schema/ob_table_schema.h" +#include "share/schema/ob_schema_service_sql_impl.h" +#include "share/schema/ob_schema_struct.h" +#include "share/tablet/ob_tablet_to_table_history_operator.h" // ObTabletToTableHistoryOperator +#include "sql/resolver/ddl/ob_ddl_resolver.h" +#include "sql/resolver/ob_resolver_utils.h" + +namespace oceanbase +{ +using namespace common; +using namespace obrpc; +using namespace share; +using namespace share::schema; +namespace rootserver +{ +ObPartitionExchange::ObPartitionExchange(ObDDLService &ddl_service) + : ddl_service_(ddl_service) +{ +} + +ObPartitionExchange::~ObPartitionExchange() +{ +} + +int ObPartitionExchange::check_and_exchange_partition(const obrpc::ObExchangePartitionArg &arg, obrpc::ObAlterTableRes &res, ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = arg.tenant_id_; + const ObTableSchema *base_table_schema = NULL; + const ObTableSchema *inc_table_schema = NULL; + bool is_oracle_mode = false; + if (OB_UNLIKELY(!ddl_service_.is_inited())) { + ret = OB_INNER_STAT_ERROR; + LOG_WARN("ddl_service not init", K(ret)); + } else if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, arg.base_table_id_, base_table_schema))) { + LOG_WARN("failed to get base table schema", K(ret), K(tenant_id), K(arg.base_table_id_)); + } else if (OB_ISNULL(base_table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not found", K(ret), K(arg)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, arg.inc_table_id_, inc_table_schema))) { + LOG_WARN("failed to get inc table schema", K(ret), K(tenant_id), K(arg.inc_table_id_)); + } else if (OB_ISNULL(inc_table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not found", K(ret), K(arg)); + } else if (OB_FAIL(base_table_schema->check_if_oracle_compat_mode(is_oracle_mode))) { + LOG_WARN("check_if_oracle_compat_mode failed", K(ret), K(is_oracle_mode)); + } else if (OB_FAIL(check_partition_exchange_conditions_(arg, *base_table_schema, *inc_table_schema, is_oracle_mode, schema_guard))) { + LOG_WARN("fail to check partition exchange conditions", K(ret), K(arg), KPC(base_table_schema), KPC(inc_table_schema), K(is_oracle_mode)); + } else if (OB_FAIL(do_exchange_partition_(arg, res, *base_table_schema, *inc_table_schema, is_oracle_mode, schema_guard))) { + LOG_WARN("fail to do exchange partition", K(ret), K(arg), K(res), KPC(base_table_schema), KPC(inc_table_schema), K(is_oracle_mode)); + } + return ret; +} + +int ObPartitionExchange::check_partition_exchange_conditions_(const obrpc::ObExchangePartitionArg &arg, const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode, ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!base_table_schema.is_partitioned_table() || inc_table_schema.is_partitioned_table())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table type of exchanging partition tables don't match the conditions", K(ret), K(base_table_schema.is_partitioned_table()), K(inc_table_schema.is_partitioned_table())); + LOG_USER_ERROR(OB_OP_NOT_ALLOW, "exchange partition table type"); + } else if (OB_UNLIKELY(!in_supported_table_type_white_list_(base_table_schema) || !in_supported_table_type_white_list_(inc_table_schema))) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("exchange partition table is not user table", K(ret), K(base_table_schema.is_user_table()), K(base_table_schema.is_ctas_tmp_table()), K(inc_table_schema.is_user_table()), K(inc_table_schema.is_ctas_tmp_table())); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "Partition exchange operations for non-user tables are"); + } else if (OB_FAIL(used_pt_nt_id_map_.create(MAX_INDEXES, lib::ObLabel("ExchangePart")))) { + LOG_WARN("failed to create used pt nt id map", K(ret)); + } else if (OB_FAIL(used_table_to_tablet_id_map_.create(MAX_INDEXES, lib::ObLabel("ExchangePart")))) { + LOG_WARN("failed to create used pt nt tablet id map", K(ret)); + } else if (OB_FAIL(check_data_table_partition_exchange_conditions_(base_table_schema, inc_table_schema, arg.base_table_part_name_, arg.exchange_partition_level_, is_oracle_mode))) { + LOG_WARN("failed to check data table partition exchange conditions", K(ret), K(base_table_schema), K(inc_table_schema), K(arg), K(is_oracle_mode)); + } else if (OB_FAIL(generate_auxiliary_table_mapping_(base_table_schema, + inc_table_schema, + arg.base_table_part_name_, + arg.exchange_partition_level_, + is_oracle_mode, + schema_guard))) { + LOG_WARN("fail to generate auxiliary table mapping", K(ret), K(base_table_schema), K(inc_table_schema), K(is_oracle_mode)); + } + return ret; +} + +int ObPartitionExchange::do_exchange_partition_(const obrpc::ObExchangePartitionArg &arg, obrpc::ObAlterTableRes &res, const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode, ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = arg.tenant_id_; + int64_t schema_version = OB_INVALID_VERSION; + ObDDLSQLTransaction trans(&ddl_service_.get_schema_service()); + ObDDLOperator ddl_operator(ddl_service_.get_schema_service(), ddl_service_.get_sql_proxy()); + if (OB_FAIL(schema_guard.get_schema_version(tenant_id, schema_version))) { + LOG_WARN("failed to get tenant schema version", K(ret), K(tenant_id), K(schema_version)); + } else if (OB_FAIL(trans.start(&ddl_service_.get_sql_proxy(), tenant_id, schema_version))) { + LOG_WARN("start transaction failed", K(ret), K(tenant_id), K(schema_version)); + } else { + if (PARTITION_LEVEL_ONE == arg.exchange_partition_level_) { + const ObPartition *data_part = nullptr; + int64_t data_partition_index = OB_INVALID_INDEX; + if (OB_FAIL(get_data_partition_and_index_(base_table_schema, arg.base_table_part_name_, data_part, data_partition_index))) { + LOG_WARN("fail to get data partition and index", K(ret), K(base_table_schema), K(arg.base_table_part_name_)); + } else if (OB_ISNULL(data_part)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("partition not found", K(ret), K(base_table_schema), K(arg.base_table_part_name_)); + } else if (OB_UNLIKELY(OB_INVALID_INDEX == data_partition_index)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid partition index", K(ret), K(base_table_schema), K(arg.base_table_part_name_)); + } else if (OB_FAIL(lock_exchange_data_table_and_partition_(tenant_id, base_table_schema, inc_table_schema, data_part->get_tablet_id(), trans))) { + LOG_WARN("fail to exchange data table partition", K(ret), K(tenant_id), K(base_table_schema), K(inc_table_schema), K(data_part->get_tablet_id())); + } else if (OB_FAIL(exchange_data_table_partition_(tenant_id, base_table_schema, inc_table_schema, *data_part, is_oracle_mode, ddl_operator, trans, schema_guard))) { + LOG_WARN("fail to exchange data table partition", K(ret), K(tenant_id), K(base_table_schema), K(inc_table_schema), KPC(data_part), K(is_oracle_mode)); + } else if (OB_FAIL(exchange_auxiliary_table_partition_(tenant_id, data_partition_index, *data_part, is_oracle_mode, ddl_operator, trans, schema_guard))) { + LOG_WARN("fail to exchange auxiliary table partition", K(ret), K(tenant_id), K(data_partition_index), KPC(data_part), K(is_oracle_mode)); + } else if (OB_FAIL(set_global_storage_index_unusable_(tenant_id, base_table_schema, inc_table_schema, ddl_operator, trans, schema_guard))) { + LOG_WARN("fail to set global storage index unable", K(ret), K(tenant_id), K(base_table_schema), K(inc_table_schema)); + } + } else if (PARTITION_LEVEL_TWO == arg.exchange_partition_level_) { + const ObPartition *data_part = nullptr; + const ObSubPartition *data_subpart = nullptr; + int64_t data_partition_index = OB_INVALID_INDEX; + int64_t data_subpartition_index = OB_INVALID_INDEX; + if (OB_FAIL(get_data_subpartition_and_index_(base_table_schema, arg.base_table_part_name_, data_part, data_subpart, data_partition_index, data_subpartition_index))) { + LOG_WARN("fail to get data subpartition and index", K(ret), K(base_table_schema), K(arg.base_table_part_name_)); + } else if (OB_ISNULL(data_part) || OB_ISNULL(data_subpart)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("subpartition not found", K(ret), K(base_table_schema), K(arg.base_table_part_name_), KPC(data_part), KPC(data_subpart)); + } else if (OB_UNLIKELY(OB_INVALID_INDEX == data_partition_index || OB_INVALID_INDEX == data_subpartition_index)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subpartition index", K(ret), K(base_table_schema), K(arg.base_table_part_name_), K(data_partition_index), K(data_subpartition_index)); + } else if (OB_FAIL(lock_exchange_data_table_and_partition_(tenant_id, base_table_schema, inc_table_schema, data_subpart->get_tablet_id(), trans))) { + LOG_WARN("fail to exchange data table partition", K(ret), K(tenant_id), K(base_table_schema), K(inc_table_schema), K(data_subpart->get_tablet_id())); + } else if (OB_FAIL(exchange_data_table_subpartition_(tenant_id, base_table_schema, inc_table_schema, *data_part, *data_subpart, is_oracle_mode, ddl_operator, trans, schema_guard))) { + LOG_WARN("fail to exchange data table subpartition", K(ret), K(tenant_id), K(base_table_schema), K(inc_table_schema), KPC(data_part), KPC(data_subpart), K(is_oracle_mode)); + } else if (OB_FAIL(exchange_auxiliary_table_subpartition_(tenant_id, data_partition_index, data_subpartition_index, *data_part, *data_subpart, is_oracle_mode, ddl_operator, trans, schema_guard))) { + LOG_WARN("fail to exchange auxiliary table subpartition", K(ret), K(tenant_id), K(data_partition_index), K(data_subpartition_index), KPC(data_part), KPC(data_subpart), K(is_oracle_mode)); + } else if (OB_FAIL(set_global_storage_index_unusable_(tenant_id, base_table_schema, inc_table_schema, ddl_operator, trans, schema_guard))) { + LOG_WARN("fail to set global storage index unable", K(ret), K(tenant_id), K(base_table_schema), K(inc_table_schema)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("partition level is invalid", K(ret), K(tenant_id), K(arg.exchange_partition_level_), K(is_oracle_mode), K(base_table_schema), K(inc_table_schema)); + } + if (OB_SUCC(ret)) { + int64_t new_nt_schema_version = OB_INVALID_VERSION; + int64_t new_pt_schema_version = OB_INVALID_VERSION; + if (OB_FAIL(push_data_table_schema_version_(tenant_id, inc_table_schema, nullptr/*ddl_stmt_str*/, base_table_schema.get_table_id(), new_nt_schema_version, trans))) { + LOG_WARN("failed to push data table schema version", K(ret), K(tenant_id), K(inc_table_schema), K(base_table_schema.get_table_id())); + } else if (OB_FAIL(push_data_table_schema_version_(tenant_id, base_table_schema, &arg.ddl_stmt_str_, inc_table_schema.get_table_id(), new_pt_schema_version, trans))) { + LOG_WARN("failed to push data table schema version", K(ret), K(tenant_id), K(base_table_schema), K(arg.ddl_stmt_str_), K(inc_table_schema.get_table_id())); + } else if (OB_FAIL(adapting_cdc_changes_in_exchange_partition_(tenant_id, base_table_schema.get_table_id(), inc_table_schema.get_table_id(), trans))) { + LOG_WARN("failed to adapting cdc changes in exchange_partition", K(ret), K(tenant_id), K(base_table_schema.get_table_id()), K(inc_table_schema.get_table_id())); + } else { + res.schema_version_ = new_pt_schema_version; + } + } + } + if (trans.is_started()) { + int temp_ret = OB_SUCCESS; + if (OB_SUCCESS != (temp_ret = trans.end(OB_SUCC(ret)))) { + LOG_WARN_RET(temp_ret, "trans end failed", "is_commit", OB_SUCCESS == ret, K(temp_ret)); + ret = (OB_SUCC(ret)) ? temp_ret : ret; + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ddl_service_.publish_schema(tenant_id))) { + LOG_WARN("publish_schema failed", K(ret), K(tenant_id)); + } + return ret; +} + +int ObPartitionExchange::lock_exchange_data_table_and_partition_(const uint64_t tenant_id, const ObTableSchema &partitioned_table_schema, const ObTableSchema &non_partitioned_table_schema, const common::ObTabletID &tablet_id, ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + ObTabletIDArray tablet_ids; + if (OB_UNLIKELY(!partitioned_table_schema.is_valid() || !non_partitioned_table_schema.is_valid() || !tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schema), K(tablet_id)); + } else if (OB_FAIL(tablet_ids.push_back(tablet_id))) { + LOG_WARN("fail to push tablet id", K(ret), K(tenant_id), K(tablet_id)); + } else if (OB_FAIL(ddl_service_.lock_table(trans, non_partitioned_table_schema))) { + LOG_WARN("failed to lock non_partitioned table", K(ret), K(tenant_id), K(non_partitioned_table_schema)); + } else if (OB_FAIL(ddl_service_.lock_tablets(trans, tenant_id, partitioned_table_schema.get_table_id(), tablet_ids))) { + LOG_WARN("failed to lock tablets", K(ret), K(tenant_id), K(partitioned_table_schema.get_table_id()), K(tablet_ids)); + } + DEBUG_SYNC(BEFORE_ALTER_TABLE_EXCHANGE_PARTITION); + return ret; +} + +int ObPartitionExchange::check_data_table_partition_exchange_conditions_(const ObTableSchema &base_table_schema, + const ObTableSchema &inc_table_schema, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(exchange_partition_name.empty() || PARTITION_LEVEL_ZERO == exchange_partition_level)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(exchange_partition_name), K(exchange_partition_level)); + } else if (OB_FAIL(check_table_conditions_in_common_(base_table_schema, inc_table_schema, exchange_partition_name, exchange_partition_level, is_oracle_mode))) { + LOG_WARN("fail to check table conditions in common", K(ret), K(base_table_schema), K(inc_table_schema), K(exchange_partition_name), K(exchange_partition_level), K(is_oracle_mode)); + } else if (is_oracle_mode) { + if (OB_FAIL(check_table_conditions_in_oracle_mode_(base_table_schema, inc_table_schema))) { + LOG_WARN("fail to check table conditions in oracle mode", K(ret), K(base_table_schema), K(inc_table_schema)); + } + } else if (OB_FAIL(check_table_conditions_in_mysql_mode_(base_table_schema, inc_table_schema))) { + LOG_WARN("fail to check table conditions in mysql mode", K(ret), K(base_table_schema), K(inc_table_schema)); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(check_table_all_column_conditions_(base_table_schema, inc_table_schema, is_oracle_mode))) { + LOG_WARN("fail to check table all column conditions", K(ret), K(base_table_schema), K(inc_table_schema)); + } else if (OB_FAIL(check_table_constraints_(base_table_schema, inc_table_schema, is_oracle_mode))) { + LOG_WARN("fail to check table constraints", K(ret), K(base_table_schema), K(inc_table_schema), K(is_oracle_mode)); + } + } + return ret; +} + +int ObPartitionExchange::check_table_conditions_in_common_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const ObString &exchange_partition_name, const ObPartitionLevel exchange_partition_level, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + bool is_base_table_column_store = false; + bool is_inc_table_column_store = false; + bool is_equal = false; + if (OB_UNLIKELY(exchange_partition_name.empty() || PARTITION_LEVEL_ZERO == exchange_partition_level)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(exchange_partition_name), K(exchange_partition_level)); + } else if (OB_UNLIKELY(!base_table_schema.check_can_do_ddl() || !inc_table_schema.check_can_do_ddl())) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("offline ddl is being executed, other ddl operations are not allowed", K(ret), K(base_table_schema.check_can_do_ddl()), K(inc_table_schema.check_can_do_ddl())); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "execute ddl while other ddl operations are executing long running ddl"); + } else if (OB_UNLIKELY(base_table_schema.get_tenant_id() != inc_table_schema.get_tenant_id())) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("tenant id of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_tenant_id()), K(inc_table_schema.get_tenant_id())); + LOG_USER_ERROR(OB_OP_NOT_ALLOW, "exchange partition tables belong to different tenants is"); + } else if (base_table_schema.is_in_splitting() || inc_table_schema.is_in_splitting()) { + //TODO ddl must not execute on splitting table due to split not unstable + ret = OB_OP_NOT_ALLOW; + LOG_WARN("table is physical or logical split can not split", K(ret), K(base_table_schema), K(inc_table_schema)); + LOG_USER_ERROR(OB_OP_NOT_ALLOW, "table is in physial or logical split, ddl operation"); + } else if (OB_UNLIKELY(share::ObDuplicateScope::DUPLICATE_SCOPE_NONE != base_table_schema.get_duplicate_scope() || share::ObDuplicateScope::DUPLICATE_SCOPE_NONE != inc_table_schema.get_duplicate_scope())) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("can't support exchanging parition between duplicate tables", K(ret), K(base_table_schema.get_duplicate_scope()), K(inc_table_schema.get_duplicate_scope())); + LOG_USER_ERROR(OB_OP_NOT_ALLOW, "exchange partition in duplicate tables"); + } else if (OB_UNLIKELY(base_table_schema.is_aux_table() != inc_table_schema.is_aux_table())) { + LOG_WARN("aux table attribute of exchanging partition tables are not equal", K(ret), K(base_table_schema.is_aux_table()), K(inc_table_schema.is_aux_table())); + } else if (OB_FAIL(check_partition_and_table_tablespace_(base_table_schema, inc_table_schema, exchange_partition_name, exchange_partition_level, is_oracle_mode))) { + LOG_WARN("fail to check partition and table tablespace", K(ret), K(base_table_schema), K(inc_table_schema), K(exchange_partition_name), K(exchange_partition_level), K(is_oracle_mode)); + } else if (OB_FAIL(check_table_rowkey_infos_(base_table_schema, inc_table_schema, is_oracle_mode))) { + LOG_WARN("fail to check table rowkey infos", K(ret), K(base_table_schema), K(inc_table_schema), K(is_oracle_mode)); + } else if (OB_FAIL(check_table_index_infos_(base_table_schema, inc_table_schema, is_oracle_mode))) { + LOG_WARN("fail to check table index infos", K(ret), K(base_table_schema), K(inc_table_schema), K(is_oracle_mode)); + } else if (OB_FAIL(check_table_lob_infos_(base_table_schema, inc_table_schema, is_oracle_mode))) { + LOG_WARN("fail to check table lob infos", K(ret), K(base_table_schema), K(inc_table_schema), K(is_oracle_mode)); + } else { + is_equal = false; + if (OB_UNLIKELY(base_table_schema.get_tablegroup_id() != inc_table_schema.get_tablegroup_id())) { + LOG_WARN("the tablegroup id of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_tablegroup_id()), K(inc_table_schema.get_tablegroup_id())); + } else if (OB_UNLIKELY(base_table_schema.get_load_type() != inc_table_schema.get_load_type())) { + LOG_WARN("the load type of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_load_type()), K(inc_table_schema.get_load_type())); + } else if (OB_UNLIKELY(share::schema::TABLE_DEF_TYPE_USER != base_table_schema.get_def_type() || share::schema::TABLE_DEF_TYPE_USER != inc_table_schema.get_def_type())) { + LOG_WARN("not support to exchange partition in internal table", K(ret), K(base_table_schema.get_def_type()), K(inc_table_schema.get_def_type())); + } else if (OB_UNLIKELY(base_table_schema.is_read_only() != inc_table_schema.is_read_only())) { + if (is_oracle_mode) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("update operation not allowed on table", K(ret), K(base_table_schema.is_read_only()), K(base_table_schema.is_read_only())); + LOG_USER_ERROR(OB_OP_NOT_ALLOW, "update operation"); + } + LOG_WARN("read only attribute of exchanging partition tables are not equal", K(ret), K(base_table_schema.is_read_only()), K(inc_table_schema.is_read_only())); + } else if (OB_UNLIKELY(0 != strcmp(base_table_schema.get_compress_func_name(), inc_table_schema.get_compress_func_name()))) { + ret = OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION; + LOG_WARN("compress func name of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_compress_func_name()), K(inc_table_schema.get_compress_func_name())); + LOG_USER_ERROR(OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION, "ROW_FORMAT"); + } else if (OB_UNLIKELY(base_table_schema.get_store_format() != inc_table_schema.get_store_format())) { + ret = OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION; + LOG_WARN("store format of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_store_format()), K(inc_table_schema.get_store_format())); + LOG_USER_ERROR(OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION, "ROW_FORMAT"); + } else if (OB_FAIL(base_table_schema.get_is_column_store(is_base_table_column_store))) { + LOG_WARN("fail to get table is column store", K(ret), K(is_base_table_column_store)); + } else if (OB_FAIL(inc_table_schema.get_is_column_store(is_inc_table_column_store))) { + LOG_WARN("fail to get table is column store", K(ret), K(is_inc_table_column_store)); + } else if (OB_UNLIKELY(is_base_table_column_store != is_inc_table_column_store)) { + ret = OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION; + LOG_WARN("the column store of exchanging partition tables are not equal", K(ret), K(is_base_table_column_store), K(is_inc_table_column_store)); + LOG_USER_ERROR(OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION, "COLUMN_STORAGE_FORMAT"); + } else if (OB_UNLIKELY(base_table_schema.is_use_bloomfilter() != inc_table_schema.is_use_bloomfilter())) { + LOG_WARN("use bloomfilter flag of exchanging partition tables are not equal", K(ret), K(base_table_schema.is_use_bloomfilter()), K(inc_table_schema.is_use_bloomfilter())); + } else if (OB_UNLIKELY(base_table_schema.get_block_size() != inc_table_schema.get_block_size())) { + LOG_WARN("block size of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_block_size()), K(inc_table_schema.get_block_size())); + } else if (OB_UNLIKELY(base_table_schema.get_collation_type() != inc_table_schema.get_collation_type())) { + LOG_WARN("collation type of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_collation_type()), K(inc_table_schema.get_collation_type())); + } else if (OB_UNLIKELY(base_table_schema.get_tablet_size() != inc_table_schema.get_tablet_size())) { + LOG_WARN("tablet size of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_tablet_size()), K(inc_table_schema.get_tablet_size())); + } else if (OB_UNLIKELY(base_table_schema.get_pctfree() != inc_table_schema.get_pctfree())) { + LOG_WARN("pctfree value of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_pctfree()), K(inc_table_schema.get_pctfree())); + } else if (OB_UNLIKELY(ObPartitionStatus::PARTITION_STATUS_ACTIVE != base_table_schema.get_partition_status() || ObPartitionStatus::PARTITION_STATUS_ACTIVE != inc_table_schema.get_partition_status())) { + LOG_WARN("partition status of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_partition_status()), K(inc_table_schema.get_partition_status())); + } else if (OB_UNLIKELY(base_table_schema.get_partition_schema_version() != inc_table_schema.get_partition_schema_version())) { + LOG_WARN("partition schema version of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_partition_schema_version()), K(inc_table_schema.get_partition_schema_version())); + } else if (OB_UNLIKELY(base_table_schema.get_storage_format_version() != inc_table_schema.get_storage_format_version())) { + LOG_WARN("storage format version of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_storage_format_version()), K(inc_table_schema.get_storage_format_version())); + } else if (OB_UNLIKELY(base_table_schema.get_table_mode() != inc_table_schema.get_table_mode())) { + LOG_WARN("table mode of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_table_mode()), K(inc_table_schema.get_table_mode())); + } else if (OB_UNLIKELY(0 != base_table_schema.get_encryption_str().compare(inc_table_schema.get_encryption_str()))) { + LOG_WARN("encryption str of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_encryption_str()), K(inc_table_schema.get_encryption_str())); + } else if (OB_UNLIKELY(base_table_schema.get_table_flags() != inc_table_schema.get_table_flags())) { + LOG_WARN("table flags of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_table_flags()), K(inc_table_schema.get_table_flags())); + } else if (OB_UNLIKELY(0 != base_table_schema.get_ttl_definition().compare(inc_table_schema.get_ttl_definition()))) { + LOG_WARN("ttl definition of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_ttl_definition()), K(inc_table_schema.get_ttl_definition())); + } else if (OB_UNLIKELY(0 != base_table_schema.get_kv_attributes().compare(inc_table_schema.get_kv_attributes()))) { + LOG_WARN("kv attributes of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_kv_attributes()), K(inc_table_schema.get_kv_attributes())); + } else if (OB_UNLIKELY(base_table_schema.get_index_using_type() != inc_table_schema.get_index_using_type())) { + LOG_WARN("index using type of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_index_using_type()), K(inc_table_schema.get_index_using_type())); + } else if (OB_UNLIKELY(base_table_schema.get_row_store_type() != inc_table_schema.get_row_store_type())) { + ret = OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION; + LOG_WARN("row store type of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_row_store_type()), K(inc_table_schema.get_row_store_type())); + LOG_USER_ERROR(OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION, "ROW_FORMAT"); + } else if (OB_UNLIKELY(base_table_schema.get_charset_type() != inc_table_schema.get_charset_type())) { + LOG_WARN("charset type of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_charset_type()), K(inc_table_schema.get_charset_type())); + } else if (OB_UNLIKELY(base_table_schema.get_compressor_type() != inc_table_schema.get_compressor_type())) { + LOG_WARN("compressor type of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_compressor_type()), K(inc_table_schema.get_compressor_type())); + } else if (OB_UNLIKELY(0 != base_table_schema.get_expire_info().compare(inc_table_schema.get_expire_info()))) { + LOG_WARN("expire info of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_expire_info()), K(inc_table_schema.get_expire_info())); + } else if (OB_UNLIKELY(base_table_schema.get_foreign_key_infos().count() != 0 || inc_table_schema.get_foreign_key_infos().count() != 0)) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "exchanging partition tables have foreign key are"); + LOG_WARN("including foreign key of exchanging partition tables", K(ret), K(base_table_schema.get_foreign_key_infos().count()), K(inc_table_schema.get_foreign_key_infos().count())); + } else { + is_equal = true; + LOG_INFO("pass table level conditions check in common", K(ret), K(base_table_schema.get_table_id()), K(inc_table_schema.get_table_id())); + } + } + if (OB_SUCC(ret) && !is_equal) { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + LOG_WARN("table conditions in common of exchange tables are not equal", K(ret), K(base_table_schema), K(inc_table_schema), K(exchange_partition_name), K(exchange_partition_level)); + } + return ret; +} + +int ObPartitionExchange::check_table_conditions_in_mysql_mode_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + if (OB_UNLIKELY((0 != base_table_schema.get_autoinc_column_id() || 0 != inc_table_schema.get_autoinc_column_id()))) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "exchanging partition tables have autoincrement column"); + LOG_WARN("exchanging partition tables have autoincrement column is not supported", K(ret), K(base_table_schema.get_autoinc_column_id()), K(base_table_schema.get_autoinc_column_id())); + } else { + is_equal = true; + } + if (OB_SUCC(ret) && !is_equal) { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + LOG_WARN("table conditions in mysql mode are not equal", K(ret), K(base_table_schema), K(inc_table_schema)); + } + return ret; +} + +int ObPartitionExchange::check_table_all_column_conditions_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + ObTableSchema::const_column_iterator base_iter_begin = base_table_schema.column_begin(); + ObTableSchema::const_column_iterator base_iter_end = base_table_schema.column_end(); + ObTableSchema::const_column_iterator inc_iter_begin = inc_table_schema.column_begin(); + ObTableSchema::const_column_iterator inc_iter_end = inc_table_schema.column_end(); + ObColumnSchemaV2 *base_table_col_schema = NULL; + ObColumnSchemaV2 *inc_table_col_schema = NULL; + while (OB_SUCC(ret) && OB_SUCC(get_next_pair_column_schema_(base_iter_begin, base_iter_end, inc_iter_begin, inc_iter_end, is_oracle_mode, base_table_col_schema, inc_table_col_schema))) { + if (OB_ISNULL(base_table_col_schema) || OB_ISNULL(inc_table_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to column schema", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } else if (OB_FAIL(check_column_level_conditions_(base_table_col_schema, inc_table_col_schema, base_table_schema.is_aux_table(), is_oracle_mode))) { + LOG_WARN("fail to check column level conditions", K(ret), K(base_table_schema), K(inc_table_schema), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(base_table_schema.is_aux_table()), K(is_oracle_mode)); + } + } + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + if (OB_FAIL(check_table_column_groups_(base_table_schema, inc_table_schema, is_oracle_mode))) { + LOG_WARN("fail to check table column groups", K(ret), K(base_table_schema), K(inc_table_schema), K(is_oracle_mode)); + } + } else { + LOG_WARN("fail to check table all column conditions", K(ret), K(base_table_schema), K(inc_table_schema), K(is_oracle_mode)); + } + return ret; +} + +int ObPartitionExchange::check_table_conditions_in_oracle_mode_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(base_table_schema.get_database_id() != inc_table_schema.get_database_id())) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "exchange partition in different databases"); + LOG_WARN("database id of exchanging partition tables are not equal in oracle mode", K(ret), K(base_table_schema.get_database_id()), K(inc_table_schema.get_database_id())); + } + return ret; +} + +int ObPartitionExchange::check_table_constraints_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + bool is_equal = true; + ObArray used_flag; + if (OB_UNLIKELY(base_table_schema.get_constraint_count() != inc_table_schema.get_constraint_count())) { + is_equal = false; + if (is_oracle_mode) { + ret = OB_ERR_CHECK_CONSTRAINT_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } + LOG_WARN("constraints num of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_constraint_count()), K(inc_table_schema.get_constraint_count())); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < base_table_schema.get_constraint_count(); i++) { + if (OB_FAIL(used_flag.push_back(false))) { + LOG_WARN("fail to push back", K(ret)); + } + } + if (OB_SUCC(ret)) { + ObTableSchema::const_constraint_iterator base_iter = base_table_schema.constraint_begin(); + ObTableSchema::const_constraint_iterator inc_iter = inc_table_schema.constraint_begin(); + for (ObTableSchema::const_constraint_iterator base_iter = base_table_schema.constraint_begin(); OB_SUCC(ret) && is_equal && base_iter != base_table_schema.constraint_end(); ++base_iter) { + if (OB_ISNULL(base_iter) || OB_ISNULL(*base_iter)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("constraint is null", K(ret)); + } else { + int64_t loc = 0; + bool found_same_constraint = false; + for (ObTableSchema::const_constraint_iterator inc_iter = inc_table_schema.constraint_begin(); OB_SUCC(ret) && !found_same_constraint && inc_iter != inc_table_schema.constraint_end(); ++inc_iter, loc++) { + if (OB_ISNULL(inc_iter) || OB_ISNULL(*inc_iter)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("constraint is null", K(ret)); + } else if (used_flag[loc]) { + } else if ((*base_iter)->is_match_partition_exchange_constraint_conditions(*(*inc_iter))) { + found_same_constraint = true; + used_flag[loc] = true; + } + } + if (OB_SUCC(ret) && !found_same_constraint) { + if (is_oracle_mode) { + if (CONSTRAINT_TYPE_PRIMARY_KEY == (*base_iter)->get_constraint_type() || CONSTRAINT_TYPE_NOT_NULL == (*base_iter)->get_constraint_type()) { + ret = OB_ERR_COLUMN_TYPE_OR_SIZE_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_ERR_CHECK_CONSTRAINT_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } + } + is_equal = false; + LOG_WARN("check constraints of exchanging partition tables are not equal", K(ret)); + } + } + } + } + } + if (OB_SUCC(ret) && !is_equal) { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + LOG_WARN("check constraints of exchanging partition tables are not equal", K(ret)); + } + return ret; +} + +int ObPartitionExchange::check_column_level_conditions_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_aux_table_column, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(base_table_col_schema) || OB_ISNULL(inc_table_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column schema is null", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } else if (!is_oracle_mode) { + if (OB_FAIL(check_column_conditions_in_mysql_mode_(base_table_col_schema, inc_table_col_schema, is_aux_table_column))) { + LOG_WARN("fail to check column conditions in mysql mode", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_aux_table_column)); + } + } else if (OB_FAIL(check_column_conditions_in_oracle_mode_(base_table_col_schema, inc_table_col_schema, is_aux_table_column))) { + LOG_WARN("fail to check column conditions in oracle mode", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_aux_table_column)); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(check_column_conditions_in_common_(base_table_col_schema, inc_table_col_schema, is_oracle_mode))) { + LOG_WARN("fail to check column conditions in common", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_oracle_mode)); + } + } + return ret; +} +// TODO: If the partition exchange tables contain instant columns, an error is reported now. In subsequent versions, if there are instant columns, both base_table_col_schema and inc_table_col_schema need to be instant columns, and the instant columns need not require the same column name. +int ObPartitionExchange::check_column_conditions_in_common_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + if (OB_ISNULL(base_table_col_schema) || OB_ISNULL(inc_table_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column schema is null", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } else if (OB_UNLIKELY(base_table_col_schema->get_tenant_id() != inc_table_col_schema->get_tenant_id())) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("column tenant id of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_tenant_id()), K(inc_table_col_schema->get_tenant_id())); + LOG_USER_ERROR(OB_OP_NOT_ALLOW, "exchange partition tables belong to different tenants is"); + } else if (OB_UNLIKELY(base_table_col_schema->is_unused() || inc_table_col_schema->is_unused())) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "exchanging partition tables have instant column"); + LOG_WARN("exchanging partition tables have instant column is not supported", K(ret), K(base_table_col_schema->is_unused()), K(inc_table_col_schema->is_unused())); + } else if (OB_UNLIKELY(base_table_col_schema->get_rowkey_position() != inc_table_col_schema->get_rowkey_position())) { + LOG_WARN("column rowkey position of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_rowkey_position()), K(inc_table_col_schema->get_rowkey_position())); + } else if (OB_UNLIKELY(base_table_col_schema->get_index_position() != inc_table_col_schema->get_index_position())) { + LOG_WARN("column index position of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_index_position()), K(inc_table_col_schema->get_index_position())); + } else if (OB_UNLIKELY(base_table_col_schema->get_order_in_rowkey() != inc_table_col_schema->get_order_in_rowkey())) { + LOG_WARN("column order in rowkey of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_order_in_rowkey()), K(inc_table_col_schema->get_order_in_rowkey())); + } else if (OB_UNLIKELY(base_table_col_schema->get_data_length() != inc_table_col_schema->get_data_length())) { + LOG_WARN("column data length of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_data_length()), K(inc_table_col_schema->get_data_length())); + } else if (OB_UNLIKELY(base_table_col_schema->get_data_precision() != inc_table_col_schema->get_data_precision())) { + LOG_WARN("column data precision of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_data_precision()), K(inc_table_col_schema->get_data_precision())); + } else if (OB_UNLIKELY(base_table_col_schema->get_data_scale() != inc_table_col_schema->get_data_scale())) { + LOG_WARN("column data scale of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_data_scale()), K(inc_table_col_schema->get_data_scale())); + } else if (OB_UNLIKELY(base_table_col_schema->is_zero_fill() != inc_table_col_schema->is_zero_fill())) { + LOG_WARN("column is zero fill option of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_zero_fill()), K(inc_table_col_schema->is_zero_fill())); + } else if (OB_UNLIKELY(base_table_col_schema->is_autoincrement() != inc_table_col_schema->is_autoincrement())) { + LOG_WARN("column is autoincrement option of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_autoincrement()), K(inc_table_col_schema->is_autoincrement())); + } else if (OB_UNLIKELY(base_table_col_schema->is_hidden() != inc_table_col_schema->is_hidden())) { + LOG_WARN("column is hidden option of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_hidden()), K(inc_table_col_schema->is_hidden())); + } else if (OB_UNLIKELY(base_table_col_schema->get_collation_type() != inc_table_col_schema->get_collation_type())) { + LOG_WARN("column collation type of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_collation_type()), K(inc_table_col_schema->get_collation_type())); + } else if (OB_UNLIKELY(base_table_col_schema->get_srs_id() != inc_table_col_schema->get_srs_id())) { + LOG_WARN("column srs id of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_srs_id()), K(inc_table_col_schema->get_srs_id())); + } else if (OB_UNLIKELY(base_table_col_schema->get_sub_data_type() != inc_table_col_schema->get_sub_data_type())) { + LOG_WARN("column sub data type of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_sub_data_type()), K(inc_table_col_schema->get_sub_data_type())); + } else if (OB_UNLIKELY(base_table_col_schema->is_rowkey_column() != inc_table_col_schema->is_rowkey_column())) { + LOG_WARN("is rowkey column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_rowkey_column()), K(inc_table_col_schema->is_rowkey_column())); + } else if (OB_UNLIKELY(base_table_col_schema->get_data_type() != inc_table_col_schema->get_data_type())) { + LOG_WARN("column data type of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_data_type()), K(inc_table_col_schema->get_data_type())); + } else if (OB_UNLIKELY(base_table_col_schema->get_lob_chunk_size() != inc_table_col_schema->get_lob_chunk_size())) { + LOG_WARN("lob chunk size of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_lob_chunk_size()), K(inc_table_col_schema->get_lob_chunk_size())); + } else if (OB_UNLIKELY(!(base_table_col_schema->get_local_session_var() == inc_table_col_schema->get_local_session_var()))) { + LOG_WARN("local session var of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_local_session_var()), K(inc_table_col_schema->get_local_session_var())); + } else if (OB_UNLIKELY(base_table_col_schema->get_skip_index_attr().get_packed_value() != inc_table_col_schema->get_skip_index_attr().get_packed_value())) { + LOG_WARN("column skip index attr of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_skip_index_attr()), K(inc_table_col_schema->get_skip_index_attr())); + } else if (OB_UNLIKELY(base_table_col_schema->get_udt_set_id() != inc_table_col_schema->get_udt_set_id())) { + LOG_WARN("column udt set id of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_udt_set_id()), K(inc_table_col_schema->get_udt_set_id())); + } else if (OB_UNLIKELY(base_table_col_schema->is_nullable() != inc_table_col_schema->is_nullable())) { + LOG_WARN("column is nullable attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_nullable()), K(inc_table_col_schema->is_nullable())); + } else if (OB_UNLIKELY(base_table_col_schema->is_not_null_rely_column() != inc_table_col_schema->is_not_null_rely_column())) { + LOG_WARN("is not null rely column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_not_null_rely_column()), K(inc_table_col_schema->is_not_null_rely_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_not_null_enable_column() != inc_table_col_schema->is_not_null_enable_column())) { + LOG_WARN("is not null enable column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_not_null_enable_column()), K(inc_table_col_schema->is_not_null_enable_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_not_null_validate_column() != inc_table_col_schema->is_not_null_validate_column())) { + LOG_WARN("is not null validate column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_not_null_validate_column()), K(inc_table_col_schema->is_not_null_validate_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_invisible_column() != inc_table_col_schema->is_invisible_column())) { + LOG_WARN("is visible column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_invisible_column()), K(inc_table_col_schema->is_invisible_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_xmltype() != inc_table_col_schema->is_xmltype())) { + LOG_WARN("is xmltype column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_xmltype()), K(inc_table_col_schema->is_xmltype())); + } else if (OB_FAIL(check_column_flags_(base_table_col_schema, inc_table_col_schema, is_equal))) { + LOG_WARN("fail to check column flags", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_equal)); + } else if (!is_equal) { + LOG_WARN("column flags of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_column_flags()), K(inc_table_col_schema->get_column_flags()), K(is_equal)); + } else if (OB_FAIL(compare_column_extended_type_info_(base_table_col_schema->get_extended_type_info(), inc_table_col_schema->get_extended_type_info(), is_equal))) { + LOG_WARN("fail to compare column extended type info", K(ret), K(base_table_col_schema->get_extended_type_info()), K(inc_table_col_schema->get_extended_type_info()), K(is_equal)); + } else if (!is_equal) { + LOG_WARN("column extended type info count of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->get_extended_type_info()), K(inc_table_col_schema->get_extended_type_info()), K(is_equal)); + } else if (OB_FAIL(check_generate_column_conditions_(base_table_col_schema, inc_table_col_schema, is_equal))) { + LOG_WARN("fail to check generate column conditions", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_equal)); + } else if (!is_equal) { + LOG_WARN("generate column conditions of exchanging partition tables are not equal", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_equal)); + } else { + is_equal = true; + } + if (OB_SUCC(ret) && !is_equal) { + if (is_oracle_mode) { + ret = OB_ERR_COLUMN_TYPE_OR_SIZE_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("all column conditions of exchange tables are not equal in common", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_oracle_mode)); + } + return ret; +} + +int ObPartitionExchange::check_column_conditions_in_mysql_mode_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_aux_table_column) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + lib::CompatModeGuard guard(lib::Worker::CompatMode::MYSQL); + if (OB_ISNULL(base_table_col_schema) || OB_ISNULL(inc_table_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column schema is null", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } else { + ObColumnNameHashWrapper base_column_key(base_table_col_schema->get_column_name_str()); + ObColumnNameHashWrapper inc_column_key(inc_table_col_schema->get_column_name_str()); + //In the auxiliary table, the column names of redundant generated columns produced by function indexes are not required to be the same, as other columns of the indexed table from the data table, which has already been compared. + if (OB_UNLIKELY(!is_aux_table_column && !(base_column_key == inc_column_key))) { + LOG_WARN("column name of exchanging partition tables are not equal", K(ret), K(is_aux_table_column), K(base_table_col_schema->get_column_name_str()), K(inc_table_col_schema->get_column_name_str())); + } else if (OB_UNLIKELY(base_table_col_schema->is_on_update_current_timestamp() != inc_table_col_schema->is_on_update_current_timestamp())) { + LOG_WARN("column is on update_current_timestamp attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_on_update_current_timestamp()), K(inc_table_col_schema->is_on_update_current_timestamp())); + } else if (OB_FAIL(check_column_default_value_(base_table_col_schema, inc_table_col_schema, false/*is_oracle_mode*/, is_equal))) { + LOG_WARN("fail to check column default value", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_equal)); + } else if (!is_equal) { + LOG_WARN("default value of exchanging partition tables are not equal", K(ret)); + } else { + is_equal = true; + } + } + if (OB_SUCC(ret) && !is_equal) { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + LOG_WARN("all column conditions of exchange tables are not equal in mysql mode", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } + return ret; +} + +int ObPartitionExchange::check_column_conditions_in_oracle_mode_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_aux_table_column) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + lib::CompatModeGuard guard(lib::Worker::CompatMode::ORACLE); + if (OB_ISNULL(base_table_col_schema) || OB_ISNULL(inc_table_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column schema is null", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } else { + ObColumnNameHashWrapper base_column_key(base_table_col_schema->get_column_name_str()); + ObColumnNameHashWrapper inc_column_key(inc_table_col_schema->get_column_name_str()); + //In the auxiliary table, the column names of redundant generated columns produced by function indexes are not required to be the same, as other columns of the indexed table from the data table, which has already been compared. + if (OB_UNLIKELY(!is_aux_table_column && !(base_column_key == inc_column_key))) { + LOG_WARN("column name of exchanging partition tables are not equal", K(ret), K(is_aux_table_column), K(base_table_col_schema->get_column_name_str()), K(inc_table_col_schema->get_column_name_str())); + } else if (OB_UNLIKELY(base_table_col_schema->is_identity_column() || inc_table_col_schema->is_identity_column())) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "exchanging partition tables have identity column"); + LOG_WARN("exchanging partition tables have identity column is not supported", K(ret), K(base_table_col_schema->is_identity_column()), K(inc_table_col_schema->is_identity_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_identity_column() != inc_table_col_schema->is_identity_column())) { + LOG_WARN("is identity column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_identity_column()), K(inc_table_col_schema->is_identity_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_default_on_null_identity_column() != inc_table_col_schema->is_default_on_null_identity_column())) { + LOG_WARN("is default on null identity column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_default_on_null_identity_column()), K(inc_table_col_schema->is_default_on_null_identity_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_always_identity_column() != inc_table_col_schema->is_always_identity_column())) { + LOG_WARN("is always identity column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_always_identity_column()), K(inc_table_col_schema->is_always_identity_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_default_identity_column() != inc_table_col_schema->is_default_identity_column())) { + LOG_WARN("is default identity column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_default_identity_column()), K(inc_table_col_schema->is_default_identity_column())); + } else if (OB_FAIL(check_column_default_value_(base_table_col_schema, inc_table_col_schema, true/*is_oracle_mode*/, is_equal))) { + LOG_WARN("fail to check column default value", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema), K(is_equal)); + } else if (!is_equal) { + LOG_WARN("default value of exchanging partition tables are not equal", K(ret)); + } else { + is_equal = true; + } + } + if (OB_SUCC(ret) && !is_equal) { + ret = OB_ERR_COLUMN_TYPE_OR_SIZE_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + LOG_WARN("all column conditions of exchange tables are not equal in oracle mode", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } + return ret; +} + +int ObPartitionExchange::check_generate_column_conditions_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, bool &is_equal) +{ + int ret = OB_SUCCESS; + is_equal = true; + ObString base_col_expr_str; + ObString inc_col_expr_str; + if (OB_ISNULL(base_table_col_schema) || OB_ISNULL(inc_table_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column schema is null", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } else if (OB_UNLIKELY(base_table_col_schema->is_virtual_generated_column() != inc_table_col_schema->is_virtual_generated_column())) { + ret = OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN; + LOG_WARN("virtual generated column of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_virtual_generated_column()), K(inc_table_col_schema->is_virtual_generated_column())); + LOG_USER_ERROR(OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, "Exchanging partitions for non-generated columns"); + } else if (OB_UNLIKELY(base_table_col_schema->is_stored_generated_column() != inc_table_col_schema->is_stored_generated_column())) { + ret = OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN; + LOG_WARN("stored generated column of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_stored_generated_column()), K(inc_table_col_schema->is_stored_generated_column())); + LOG_USER_ERROR(OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, "Exchanging partitions for non-generated columns"); + } else if (base_table_col_schema->is_stored_generated_column() && inc_table_col_schema->is_stored_generated_column()) { + if (OB_FAIL(base_table_col_schema->get_cur_default_value().get_string(base_col_expr_str))) { + LOG_WARN("fail to get base column cur default value str", K(ret), KPC(base_table_col_schema), K(base_col_expr_str)); + } else if (OB_FAIL(inc_table_col_schema->get_cur_default_value().get_string(inc_col_expr_str))) { + LOG_WARN("fail to get inc column cur default value str", K(ret), KPC(inc_table_col_schema), K(inc_col_expr_str)); + } else if (OB_UNLIKELY(0 != base_col_expr_str.compare(inc_col_expr_str))) { + is_equal = false; + LOG_WARN("stored generated column expr strs are not equal", K(ret), K(base_col_expr_str), K(inc_col_expr_str)); + } + } + return ret; +} +int ObPartitionExchange::check_column_flags_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, bool &is_equal) +{ + int ret = OB_SUCCESS; + is_equal = false; + if (OB_ISNULL(base_table_col_schema) || OB_ISNULL(inc_table_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column schema is null", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } else if (OB_UNLIKELY(base_table_col_schema->has_not_null_constraint() != inc_table_col_schema->has_not_null_constraint())) { + LOG_WARN("has not null column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->has_not_null_constraint()), K(inc_table_col_schema->has_not_null_constraint())); + } else if (OB_UNLIKELY(base_table_col_schema->is_fulltext_column() != inc_table_col_schema->is_fulltext_column())) { + LOG_WARN("is full text column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_fulltext_column()), K(inc_table_col_schema->is_fulltext_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_primary_vp_column() != inc_table_col_schema->is_primary_vp_column())) { + LOG_WARN("is primary vp column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_primary_vp_column()), K(inc_table_col_schema->is_primary_vp_column())); + } else if (OB_UNLIKELY(base_table_col_schema->is_aux_vp_column() != inc_table_col_schema->is_aux_vp_column())) { + LOG_WARN("is aux vp column attribute of exchanging partition tables are not equal", K(ret), K(base_table_col_schema->is_aux_vp_column()), K(inc_table_col_schema->is_aux_vp_column())); + } else { + is_equal = true; + } + return ret; +} + +int ObPartitionExchange::check_column_default_value_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_oracle_mode, bool &is_equal) +{ + int ret = OB_SUCCESS; + is_equal = true; + if (OB_ISNULL(base_table_col_schema) || OB_ISNULL(inc_table_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column schema is null", K(ret), KPC(base_table_col_schema), KPC(inc_table_col_schema)); + } else if (base_table_col_schema->is_virtual_generated_column() && inc_table_col_schema->is_virtual_generated_column()) { + } else { + ObString base_col_expr_str; + ObString inc_col_expr_str; + ObObj base_orig_default_value = base_table_col_schema->get_orig_default_value(); + ObObj inc_orig_default_value = inc_table_col_schema->get_orig_default_value(); + ObObj base_cur_default_value = base_table_col_schema->get_cur_default_value(); + ObObj inc_cur_default_value = inc_table_col_schema->get_cur_default_value(); + if (OB_FAIL(compare_default_value_(base_orig_default_value, inc_orig_default_value, is_oracle_mode, is_equal))) { + LOG_WARN("fail to compare orig default value", K(ret), K(base_orig_default_value), K(inc_orig_default_value), K(is_oracle_mode)); + } else if (!is_equal) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "exchanging partition tables define different default values in alter table add column ddl operation"); + LOG_WARN("orig default value are not equal", K(ret), K(base_orig_default_value), K(inc_orig_default_value), K(is_oracle_mode), K(is_equal)); + } else if (OB_FAIL(compare_default_value_(base_cur_default_value, inc_cur_default_value, is_oracle_mode, is_equal))) { + LOG_WARN("fail to compare cur default value", K(ret), K(base_cur_default_value), K(inc_cur_default_value), K(is_oracle_mode)); + } else if (!is_equal) { + LOG_WARN("cur default value are not equal", K(ret), K(base_cur_default_value), K(inc_cur_default_value), K(is_oracle_mode), K(is_equal)); + } + } + return ret; +} + +int ObPartitionExchange::compare_default_value_(ObObj &l_value, ObObj &r_value, const bool is_oracle_mode, bool &is_equal) +{ + int ret = OB_SUCCESS; + is_equal = false; + int cmp = 0; + if (OB_UNLIKELY(l_value.is_null() != r_value.is_null())) { + LOG_WARN("default value is_null are not equal", K(ret), K(l_value), K(r_value)); + } else if (l_value.is_null() && r_value.is_null()) { + is_equal = true; + } else if (OB_UNLIKELY(l_value.get_type() != r_value.get_type())) { + LOG_WARN("default value type are not equal", K(ret), K(l_value), K(r_value)); + } else if (OB_UNLIKELY(l_value.get_collation_type() != r_value.get_collation_type())) { + LOG_WARN("default value collation type are not equal", K(ret), K(l_value), K(r_value)); + } else if (is_oracle_mode) { + ObString l_value_expr_str; + ObString r_value_expr_str; + if (OB_FAIL(l_value.get_string(l_value_expr_str))) { + LOG_WARN("fail to get column default value str", K(ret), K(l_value), K(l_value_expr_str)); + } else if (OB_FAIL(r_value.get_string(r_value_expr_str))) { + LOG_WARN("fail to get column default value str", K(ret), K(r_value), K(r_value_expr_str)); + } else if (OB_UNLIKELY(0 != l_value_expr_str.compare(r_value_expr_str))) { + LOG_WARN("default column expr strs are not equal", K(ret), K(l_value_expr_str), K(r_value_expr_str)); + } else { + is_equal = true; + } + } else if (CS_TYPE_INVALID == l_value.get_collation_type()) { + is_equal = true; + } else if (OB_FAIL(l_value.compare(r_value, cmp))) { + LOG_WARN("default value are not equal", K(ret), K(l_value), K(r_value), K(cmp)); + } else if (OB_UNLIKELY(0 != cmp)) { + LOG_WARN("default value are not equal", K(ret), K(l_value), K(r_value), K(cmp)); + } else { + is_equal = true; + } + return ret; +} + +int ObPartitionExchange::check_partition_and_table_tablespace_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const ObString &exchange_partition_name, const ObPartitionLevel exchange_partition_level, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + const ObPartition *part = nullptr; + const ObSubPartition *subpart = nullptr; + bool is_equal = false; + if (OB_UNLIKELY(exchange_partition_name.empty() || (PARTITION_LEVEL_ZERO == exchange_partition_level))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(exchange_partition_name), K(exchange_partition_level)); + } else if (OB_UNLIKELY(base_table_schema.get_tablespace_id() != inc_table_schema.get_tablespace_id())) { + LOG_WARN("tablespace id of exchanging tables are not equal", K(ret), K(base_table_schema.get_tablespace_id()), K(inc_table_schema.get_tablespace_id())); + } else if (!base_table_schema.is_aux_table() && !inc_table_schema.is_aux_table()) { + if (PARTITION_LEVEL_ONE == exchange_partition_level) { + if (OB_FAIL(base_table_schema.get_partition_by_name(exchange_partition_name, part))) { + LOG_WARN("get part by name failed", K(ret), K(exchange_partition_name), K(base_table_schema)); + } else if (OB_ISNULL(part)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("partition not found", K(ret), K(exchange_partition_name), K(base_table_schema)); + } else if (OB_UNLIKELY(OB_INVALID_INDEX != part->get_tablespace_id())) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "When the partition contains a tablespace, partition exchange is not"); + LOG_WARN("when the partition contains a tablespace, partition exchange is not supported", K(ret), K(part->get_tablespace_id()), K(inc_table_schema.get_tablespace_id())); + } else { + is_equal = true; + } + } else if (PARTITION_LEVEL_TWO == exchange_partition_level) { + if (OB_FAIL(base_table_schema.get_subpartition_by_name(exchange_partition_name, part, subpart))) { + LOG_WARN("get sub part by name failed", K(ret), K(exchange_partition_name), K(base_table_schema)); + } else if (OB_ISNULL(part) || OB_ISNULL(subpart)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("partition not found", K(ret), K(exchange_partition_name), K(base_table_schema), K(part), K(subpart)); + } else if (OB_UNLIKELY(OB_INVALID_INDEX != subpart->get_tablespace_id())) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "When the partition contains a tablespace, partition exchange is not"); + LOG_WARN("when the subpartition contains a tablespace, partition exchange is not supported", K(ret), K(subpart->get_tablespace_id()), K(inc_table_schema.get_tablespace_id())); + } else { + is_equal = true; + } + } + } else if (base_table_schema.is_aux_table() && inc_table_schema.is_aux_table()) { + is_equal = true; + } + if (OB_SUCC(ret) && !is_equal) { + if (is_oracle_mode) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "exchange partition in different tablespaces"); + } else { + ret = OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION; + LOG_USER_ERROR(OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION, "TABLESPACE"); + } + LOG_WARN("tablespace id are not equal between partition and table", K(ret), K(base_table_schema), K(inc_table_schema), K(exchange_partition_name), K(exchange_partition_level)); + } + return ret; +} + +int ObPartitionExchange::check_table_index_infos_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + if (OB_UNLIKELY(base_table_schema.get_index_column_num() != inc_table_schema.get_index_column_num())) { + LOG_WARN("index column num of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_index_column_num()), K(inc_table_schema.get_index_column_num())); + } else if (OB_FAIL(compare_two_rowkey_info_(base_table_schema.get_index_info(), inc_table_schema.get_index_info(), is_equal))) { + LOG_WARN("fail to compare two rowkey info", K(ret), K(base_table_schema.get_index_info()), K(inc_table_schema.get_index_info())); + } else if (!is_equal) { + LOG_WARN("index info of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_index_info()), K(inc_table_schema.get_index_info())); + } + if (OB_SUCC(ret) && !is_equal) { + if (is_oracle_mode) { + ret = OB_ERR_INDEX_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("table index infos of exchanging partition tables are not equal", K(ret), K(base_table_schema), K(inc_table_schema)); + } + return ret; +} + +int ObPartitionExchange::check_table_lob_infos_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + if (OB_UNLIKELY(base_table_schema.has_lob_column() != inc_table_schema.has_lob_column())) { + LOG_WARN("has lob column type of exchanging partition tables are not equal", K(ret), K(base_table_schema.has_lob_column()), K(inc_table_schema.has_lob_column())); + } else if (OB_UNLIKELY(base_table_schema.has_lob_aux_table() != inc_table_schema.has_lob_aux_table())) { + LOG_WARN("has lob aux table type of exchanging partition tables are not equal", K(ret), K(base_table_schema.has_lob_aux_table()), K(inc_table_schema.has_lob_aux_table())); + } else if (OB_UNLIKELY(base_table_schema.get_lob_inrow_threshold() != inc_table_schema.get_lob_inrow_threshold())) { + LOG_WARN("lob inrow threshold of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_lob_inrow_threshold()), K(inc_table_schema.get_lob_inrow_threshold())); + } else { + is_equal = true; + } + if (OB_SUCC(ret) && !is_equal) { + if (is_oracle_mode) { + ret = OB_ERR_COLUMN_TYPE_OR_SIZE_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("table lob infos of exchanging partition tables are not equal", K(ret), K(base_table_schema), K(inc_table_schema)); + } + return ret; +} + +int ObPartitionExchange::check_table_rowkey_infos_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + if (OB_UNLIKELY(base_table_schema.get_rowkey_column_num() != inc_table_schema.get_rowkey_column_num())) { + LOG_WARN("rowkey column num of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_rowkey_column_num()), K(inc_table_schema.get_rowkey_column_num())); + } else if (OB_UNLIKELY(base_table_schema.get_shadow_rowkey_column_num() != inc_table_schema.get_shadow_rowkey_column_num())) { + LOG_WARN("shadow rowkey column num of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_shadow_rowkey_column_num()), K(inc_table_schema.get_shadow_rowkey_column_num())); + } else if (OB_UNLIKELY(base_table_schema.get_rowkey_split_pos() != inc_table_schema.get_rowkey_split_pos())) { + LOG_WARN("rowkey split pos of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_rowkey_split_pos()), K(inc_table_schema.get_rowkey_split_pos())); + } else if (OB_FAIL(compare_two_rowkey_info_(base_table_schema.get_rowkey_info(), inc_table_schema.get_rowkey_info(), is_equal))) { + LOG_WARN("fail to compare two rowkey info", K(ret), K(base_table_schema.get_rowkey_info()), K(inc_table_schema.get_rowkey_info())); + } else if (!is_equal) { + LOG_WARN("rowkey info of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_rowkey_info()), K(inc_table_schema.get_rowkey_info())); + } else if (OB_FAIL(compare_two_rowkey_info_(base_table_schema.get_shadow_rowkey_info(), inc_table_schema.get_shadow_rowkey_info(), is_equal))) { + LOG_WARN("fail to compare two rowkey info", K(ret), K(base_table_schema.get_shadow_rowkey_info()), K(inc_table_schema.get_shadow_rowkey_info())); + } else if (!is_equal) { + LOG_WARN("shadow rowkey info of exchanging partition tables are not equal", K(ret), K(base_table_schema.get_shadow_rowkey_info()), K(inc_table_schema.get_shadow_rowkey_info())); + } + if (OB_SUCC(ret) && !is_equal) { + if (is_oracle_mode) { + ret = OB_ERR_INDEX_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("table rowkey infos of exchanging partition tables are not equal", K(ret), K(base_table_schema), K(inc_table_schema)); + } + return ret; +} + +int ObPartitionExchange::compare_two_rowkey_info_(const common::ObRowkeyInfo &l_rowkey_info, const common::ObRowkeyInfo &r_rowkey_info, bool &is_equal) +{ + int ret = OB_SUCCESS; + is_equal = true; + if (OB_UNLIKELY(l_rowkey_info.get_size() != r_rowkey_info.get_size())) { + is_equal = false; + LOG_WARN("rowkey info size are not equal", K(ret), K(l_rowkey_info.get_size()), K(r_rowkey_info.get_size())); + } else if (0 == l_rowkey_info.get_size()) { + } else { + for (int64_t i = 0; OB_SUCC(ret) && is_equal && i < l_rowkey_info.get_size(); i++) { + const ObRowkeyColumn *l_rowkey_column = l_rowkey_info.get_column(i); + const ObRowkeyColumn *r_rowkey_column = r_rowkey_info.get_column(i); + is_equal = false; + // Since the rowkey info array is already sorted, there is no need to validate the column id again. + if (OB_ISNULL(l_rowkey_column) || OB_ISNULL(r_rowkey_column)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("rowkey column is null", K(ret), KPC(l_rowkey_column), KPC(r_rowkey_column)); + } else if (OB_UNLIKELY(!l_rowkey_column->is_equal_except_column_id(*r_rowkey_column))) { + LOG_WARN("rowkey column infos are not equal", K(ret), KPC(l_rowkey_column), KPC(r_rowkey_column)); + } else { + is_equal = true; + } + } + } + return ret; +} + +int ObPartitionExchange::check_table_column_groups_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + int64_t base_store_column_group_cnt = 0; + int64_t inc_store_column_group_cnt = 0; + ObSEArray base_column_group_metas; + ObSEArray inc_column_group_metas; + if (OB_UNLIKELY(base_table_schema.get_column_group_count() != inc_table_schema.get_column_group_count())) { + LOG_WARN("column group count of exchanging tables are not equal", K(ret), K(base_table_schema.get_column_group_count()), K(inc_table_schema.get_column_group_count())); + } else if (OB_FAIL(base_table_schema.get_store_column_group_count(base_store_column_group_cnt))) { + LOG_WARN("Failed to get column group count", K(ret), K(base_table_schema)); + } else if (OB_FAIL(inc_table_schema.get_store_column_group_count(inc_store_column_group_cnt))) { + LOG_WARN("Failed to get column group count", K(ret), K(inc_table_schema)); + } else if (OB_UNLIKELY(base_store_column_group_cnt != inc_store_column_group_cnt)) { + LOG_WARN("store column group count of exchanging tables are not equal", K(ret), K(base_store_column_group_cnt), K(inc_store_column_group_cnt)); + } else if (base_store_column_group_cnt < 1) { + is_equal = true; + } else if (OB_FAIL(base_table_schema.get_store_column_groups(base_column_group_metas))) { + LOG_WARN("Failed to get column group metas", K(ret), K(base_table_schema)); + } else if (OB_FAIL(inc_table_schema.get_store_column_groups(inc_column_group_metas))) { + LOG_WARN("Failed to get column group metas", K(ret), K(inc_table_schema)); + } else if (OB_UNLIKELY(base_column_group_metas.count() != inc_column_group_metas.count())) { + LOG_WARN("column group metas count of exchanging tables are not equal", K(ret), K(base_column_group_metas.count()), K(inc_column_group_metas.count())); + } else { + is_equal = true; + for (int64_t i = 0; OB_SUCC(ret) && is_equal && i < base_column_group_metas.count(); i++) { + const ObColumnGroupSchema *base_cg_schema = nullptr; + const ObColumnGroupSchema *inc_cg_schema = nullptr; + if (OB_ISNULL(base_cg_schema = base_column_group_metas.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected null base_cg_schema", K(ret)); + } else if (OB_ISNULL(inc_cg_schema = inc_column_group_metas.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected null inc_cg_schema", K(ret)); + } else if (OB_FAIL(compare_two_column_group_schema_(base_table_schema, inc_table_schema, *base_cg_schema, *inc_cg_schema, is_oracle_mode, is_equal))) { + LOG_WARN("fail to compare two column group schema", K(ret), K(base_table_schema), K(inc_table_schema), KPC(base_cg_schema), KPC(inc_cg_schema), K(is_oracle_mode)); + } + } + } + if (OB_SUCC(ret) && !is_equal) { + ret = OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION; + LOG_WARN("column groups of exchanging partition tables are not equal", K(ret)); + LOG_USER_ERROR(OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION, "COLUMN_STORAGE_FORMAT"); + } + return ret; +} + +int ObPartitionExchange::compare_two_column_group_schema_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const ObColumnGroupSchema &base_cg_schema, const ObColumnGroupSchema &inc_cg_schema, const bool is_oracle_mode, bool &is_equal) +{ + int ret = OB_SUCCESS; + is_equal = false; + if (OB_UNLIKELY(base_table_schema.is_aux_table() != inc_table_schema.is_aux_table())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("is aux table attribute of exchange partition tables are different", K(ret), K(base_table_schema.is_aux_table()), K(inc_table_schema.is_aux_table())); + } else if (OB_UNLIKELY(!base_cg_schema.has_same_column_group_attributes_for_part_exchange(inc_cg_schema))) { + LOG_WARN("column group attributes are different", K(ret), K(base_cg_schema), K(inc_cg_schema)); + } else { + is_equal = true; + uint64_t *base_column_id_arr = base_cg_schema.get_column_ids(); + uint64_t *inc_column_id_arr = inc_cg_schema.get_column_ids(); + int64_t column_id_count = base_cg_schema.get_column_id_count(); + for (int64_t i = 0; OB_SUCC(ret) && is_equal && i < column_id_count; i++) { + const ObColumnSchemaV2 *base_cg_col_schema = NULL; + const ObColumnSchemaV2 *inc_cg_col_schema = NULL; + if (OB_ISNULL(base_cg_col_schema = base_table_schema.get_column_schema(base_column_id_arr[i]))) { + ret = OB_SCHEMA_ERROR; + LOG_WARN("fail to get column schema", K(ret), K(base_table_schema), K(base_column_id_arr[i])); + } else if (OB_ISNULL(inc_cg_col_schema = inc_table_schema.get_column_schema(inc_column_id_arr[i]))) { + ret = OB_SCHEMA_ERROR; + LOG_WARN("fail to get column schema", K(ret), K(inc_table_schema), K(inc_column_id_arr[i])); + } else if (OB_FAIL(check_column_level_conditions_(base_cg_col_schema, inc_cg_col_schema, base_table_schema.is_aux_table(), is_oracle_mode))) { + is_equal = false; + if (in_find_same_aux_table_retry_white_list_(ret)) { + ret = OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION; + LOG_USER_ERROR(OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION, "COLUMN_STORAGE_FORMAT"); + LOG_WARN("column conditions in column groups are not equal", K(ret), KPC(base_cg_col_schema), KPC(inc_cg_col_schema), K(base_table_schema.is_aux_table()), K(is_oracle_mode)); + } else { + LOG_WARN("column conditions in column groups are not equal, and ret_code not in in_find_same_aux_table_retry_white_list", K(ret), KPC(base_cg_col_schema), KPC(inc_cg_col_schema), K(base_table_schema.is_aux_table()), K(is_oracle_mode)); + } + } + } + } + return ret; +} + +int ObPartitionExchange::get_next_pair_column_schema_(ObTableSchema::const_column_iterator &base_iter_begin, + ObTableSchema::const_column_iterator &base_iter_end, + ObTableSchema::const_column_iterator &inc_iter_begin, + ObTableSchema::const_column_iterator &inc_iter_end, + const bool is_oracle_mode, + ObColumnSchemaV2 *&base_table_col_schema, + ObColumnSchemaV2 *&inc_table_col_schema) +{ + int ret = OB_SUCCESS; + base_table_col_schema = NULL; + inc_table_col_schema = NULL; + if (OB_FAIL(get_next_need_check_column_(base_iter_begin, base_iter_end, is_oracle_mode, base_table_col_schema))) { + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + if (OB_FAIL(get_next_need_check_column_(inc_iter_begin, inc_iter_end, is_oracle_mode, inc_table_col_schema))) { + if (OB_ITER_END != ret) { + LOG_WARN("error unexpected happened when iter next column schema", K(ret)); + } + } else { + if (is_oracle_mode) { + ret = OB_ERR_COLUMNS_NUMBER_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("base table schema's columns format don't match the inc_table_schema", K(ret)); + } + } else { + LOG_WARN("error unexpected happened when iter next column schema", K(ret)); + } + } else if (OB_FAIL(get_next_need_check_column_(inc_iter_begin, inc_iter_end, is_oracle_mode, inc_table_col_schema))) { + if (OB_ITER_END == ret) { + if (is_oracle_mode) { + ret = OB_ERR_COLUMNS_NUMBER_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("base table schema's columns format don't match the inc_table_schema", K(ret)); + } else { + LOG_WARN("error unexpected happened when iter next column schema", K(ret)); + } + } else if (OB_UNLIKELY(base_table_col_schema->is_hidden() != inc_table_col_schema->is_hidden())) { + if (is_oracle_mode) { + ret = OB_ERR_COLUMNS_NUMBER_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("base table schema's columns format don't match the inc_table_schema", K(ret)); + } + return ret; +} + +int ObPartitionExchange::get_next_need_check_column_(ObTableSchema::const_column_iterator &iter_begin, ObTableSchema::const_column_iterator &iter_end, const bool is_oracle_mode, ObColumnSchemaV2 *&table_col_schema) +{ + int ret = OB_SUCCESS; + bool found_col_schema = false; + for (; OB_SUCC(ret) && !found_col_schema && iter_begin != iter_end; iter_begin++) { + table_col_schema = *iter_begin; + if (OB_ISNULL(table_col_schema)) { + ret = OB_SCHEMA_ERROR; + LOG_WARN("fail to get column schema", K(ret)); + } else if (table_col_schema->is_prefix_column() || table_col_schema->is_func_idx_column()) { + } else if (!is_oracle_mode) { + found_col_schema = true; + } else if (!table_col_schema->is_virtual_generated_column()) { + found_col_schema = true; + } + } + if (OB_SUCC(ret) && !found_col_schema) { + ret = OB_ITER_END; + } + return ret; +} + +int ObPartitionExchange::set_global_storage_index_unusable_(const uint64_t tenant_id, + const ObTableSchema &partitioned_data_table_schema, + const ObTableSchema &non_partitioned_data_table_schema, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < unused_pt_index_id_.count(); i++) { + uint64_t pt_index_id = unused_pt_index_id_.at(i); + if (OB_FAIL(update_index_status_(tenant_id, + pt_index_id, + INDEX_STATUS_UNUSABLE, + partitioned_data_table_schema.get_in_offline_ddl_white_list(), + ddl_operator, + trans, + schema_guard))) { + LOG_WARN("fail to update partitioned data table index status", K(ret), K(tenant_id), K(pt_index_id), K(partitioned_data_table_schema.get_in_offline_ddl_white_list())); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < unused_nt_index_id_.count(); i++) { + uint64_t nt_index_id = unused_nt_index_id_.at(i); + if (OB_FAIL(update_index_status_(tenant_id, + nt_index_id, + INDEX_STATUS_UNUSABLE, + non_partitioned_data_table_schema.get_in_offline_ddl_white_list(), + ddl_operator, + trans, + schema_guard))) { + LOG_WARN("fail to update non partitioned data table index status", K(ret), K(tenant_id), K(nt_index_id), K(non_partitioned_data_table_schema.get_in_offline_ddl_white_list())); + } + } + } + return ret; +} + +int ObPartitionExchange::get_data_partition_and_index_(const ObTableSchema &partitioned_data_table_schema, const ObString &data_part_name, const ObPartition *&data_part, int64_t &data_partition_index) +{ + int ret = OB_SUCCESS; + int64_t part_id = 0; + data_partition_index = OB_INVALID_INDEX; + ObCheckPartitionMode check_partition_mode = CHECK_PARTITION_MODE_NORMAL; + if (OB_UNLIKELY(!partitioned_data_table_schema.is_valid() || data_part_name.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(partitioned_data_table_schema.is_valid()), K(data_part_name)); + } else if (OB_FAIL(partitioned_data_table_schema.get_partition_by_name(data_part_name, data_part))) { + LOG_WARN("get part by name failed", K(ret), K(data_part_name)); + } else if (OB_ISNULL(data_part)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("partition not found", K(ret), K(data_part_name), K(partitioned_data_table_schema)); + } else if (FALSE_IT(part_id = data_part->get_part_id())) { + } else if (OB_FAIL(partitioned_data_table_schema.get_partition_index_by_id(part_id, check_partition_mode, data_partition_index))) { + LOG_WARN("fail to get partition index by id", K(ret), K(partitioned_data_table_schema), K(part_id)); + } + return ret; +} + +int ObPartitionExchange::get_data_subpartition_and_index_(const ObTableSchema &partitioned_data_table_schema, + const ObString &data_subpart_name, + const ObPartition *&data_part, + const ObSubPartition *&data_subpart, + int64_t &data_partition_index, + int64_t &data_subpartition_index) +{ + int ret = OB_SUCCESS; + int64_t part_id = 0; + int64_t subpart_id = 0; + data_partition_index = OB_INVALID_INDEX; + data_subpartition_index = OB_INVALID_INDEX; + ObCheckPartitionMode check_partition_mode = CHECK_PARTITION_MODE_NORMAL; + if (OB_UNLIKELY(!partitioned_data_table_schema.is_valid() || data_subpart_name.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(partitioned_data_table_schema.is_valid()), K(data_subpart_name)); + } else if (OB_FAIL(partitioned_data_table_schema.get_subpartition_by_name(data_subpart_name, data_part, data_subpart))) { + LOG_WARN("get sub part by name failed", K(ret), K(partitioned_data_table_schema), K(data_subpart_name)); + } else if (OB_ISNULL(data_part) || OB_ISNULL(data_subpart)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("partition not found", K(ret), K(partitioned_data_table_schema), K(data_subpart_name)); + } else if (FALSE_IT(part_id = data_part->get_part_id())) { + } else if (OB_FAIL(partitioned_data_table_schema.get_partition_index_by_id(part_id, check_partition_mode, data_partition_index))) { + LOG_WARN("fail to get partition index", K(ret), K(partitioned_data_table_schema), K(part_id)); + } else if (FALSE_IT(subpart_id = data_subpart->get_sub_part_id())) { + } else if (OB_FAIL(data_part->get_normal_subpartition_index_by_id(subpart_id, data_subpartition_index))) { + LOG_WARN("fail to get normal subpartition index by id", K(ret), KPC(data_part), K(subpart_id)); + } + return ret; +} + +int ObPartitionExchange::exchange_data_table_partition_(const uint64_t tenant_id, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const ObPartition &part, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || !partitioned_table_schema.is_valid() || !non_partitioned_table_schema.is_valid() || !part.is_valid() || !used_table_to_tablet_id_map_.created())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(partitioned_table_schema.is_valid()), K(non_partitioned_table_schema.is_valid()), K(part.is_valid()), K(used_table_to_tablet_id_map_.created())); + } else if (OB_FAIL(used_table_to_tablet_id_map_.set_refactored(partitioned_table_schema.get_table_id(), part.get_tablet_id()))) { + LOG_WARN("fail to set refactored used table to tablet id map", K(ret), K(partitioned_table_schema.get_table_id()), K(part.get_tablet_id())); + } else if (OB_FAIL(used_table_to_tablet_id_map_.set_refactored(non_partitioned_table_schema.get_table_id(), non_partitioned_table_schema.get_tablet_id()))) { + LOG_WARN("fail to set refactored used table to tablet id map", K(ret), K(non_partitioned_table_schema.get_table_id()), K(non_partitioned_table_schema.get_tablet_id())); + } else if (OB_FAIL(exchange_partition_map_relationship_(tenant_id, + part, + partitioned_table_schema, + non_partitioned_table_schema, + is_oracle_mode, + ddl_operator, + trans, + schema_guard))) { + LOG_WARN("fail to exchange partition map relationship", K(ret), K(tenant_id), K(part), K(partitioned_table_schema), K(non_partitioned_table_schema), K(is_oracle_mode)); + } + return ret; +} + +int ObPartitionExchange::exchange_data_table_subpartition_(const uint64_t tenant_id, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const ObPartition &part, + const ObSubPartition &subpart, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || !partitioned_table_schema.is_valid() || !non_partitioned_table_schema.is_valid() || !part.is_valid() || !subpart.is_valid() || !used_table_to_tablet_id_map_.created())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(partitioned_table_schema.is_valid()), K(non_partitioned_table_schema.is_valid()), K(part.is_valid()), K(subpart.is_valid()), K(used_table_to_tablet_id_map_.created())); + } else if (OB_FAIL(used_table_to_tablet_id_map_.set_refactored(partitioned_table_schema.get_table_id(), subpart.get_tablet_id()))) { + LOG_WARN("fail to set refactored used table to tablet id map", K(ret), K(partitioned_table_schema.get_table_id()), K(subpart.get_tablet_id())); + } else if (OB_FAIL(used_table_to_tablet_id_map_.set_refactored(non_partitioned_table_schema.get_table_id(), non_partitioned_table_schema.get_tablet_id()))) { + LOG_WARN("fail to set refactored used table to tablet id map", K(ret), K(non_partitioned_table_schema.get_table_id()), K(non_partitioned_table_schema.get_tablet_id())); + } else if (OB_FAIL(exchange_subpartition_map_relationship_(tenant_id, + part, + subpart, + partitioned_table_schema, + non_partitioned_table_schema, + is_oracle_mode, + ddl_operator, + trans, + schema_guard))) { + LOG_WARN("fail to exchange subpartition map relationship", K(ret), K(tenant_id), K(part), K(subpart), K(partitioned_table_schema), K(non_partitioned_table_schema), K(is_oracle_mode)); + } + return ret; +} + +int ObPartitionExchange::exchange_auxiliary_table_partition_(const uint64_t tenant_id, + const int64_t ori_data_partition_index, + const ObPartition &ori_data_part, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + const ObPartition *part = nullptr; + const ObTableSchema *partitioned_table_schema = NULL; + const ObTableSchema *non_partitioned_table_schema = NULL; + bool is_matched = false; + ObCheckPartitionMode check_partition_mode = CHECK_PARTITION_MODE_NORMAL; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_INDEX == ori_data_partition_index || !ori_data_part.is_valid() || !used_pt_nt_id_map_.created() || !used_table_to_tablet_id_map_.created())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(ori_data_partition_index), K(ori_data_part.is_valid()), K(is_oracle_mode), K(used_pt_nt_id_map_.created()), K(used_table_to_tablet_id_map_.created())); + } else { + common::hash::ObHashMap::iterator iter; + for (iter = used_pt_nt_id_map_.begin(); OB_SUCC(ret) && iter != used_pt_nt_id_map_.end(); ++iter) { + uint64_t partitioned_table_id = iter->first; + uint64_t non_partitioned_table_id = iter->second; + if (OB_FAIL(schema_guard.get_table_schema(tenant_id, partitioned_table_id, partitioned_table_schema))) { + LOG_WARN("get table schema failed", K(ret), K(tenant_id), K(partitioned_table_id)); + } else if (OB_ISNULL(partitioned_table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema should not be null", K(ret), K(tenant_id), K(partitioned_table_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, non_partitioned_table_id, non_partitioned_table_schema))) { + LOG_WARN("get table schema failed", K(ret), K(tenant_id), K(non_partitioned_table_id)); + } else if (OB_ISNULL(non_partitioned_table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema should not be null", K(ret), K(tenant_id), K(non_partitioned_table_id)); + } else { + const schema::ObPartitionOption &pt_part_option = partitioned_table_schema->get_part_option(); + schema::ObPartitionFuncType pt_part_func_type = pt_part_option.get_part_func_type(); + if (OB_FAIL(partitioned_table_schema->get_partition_by_partition_index(ori_data_partition_index, check_partition_mode, part))) { + LOG_WARN("get_partition_by_partition_index fail", K(ret), K(ori_data_partition_index), KPC(partitioned_table_schema)); + } else if (OB_ISNULL(part)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("partition not found", K(ret), K(ori_data_partition_index), KPC(partitioned_table_schema)); + } else if (OB_FAIL(ddl_service_.check_same_partition(is_oracle_mode, ori_data_part, *part, pt_part_func_type, is_matched))) { + LOG_WARN("fail to check ori_table_part and ori_aux_part is the same", K(ret), K(is_oracle_mode), K(ori_data_part), KPC(part), K(pt_part_func_type)); + } else if (OB_UNLIKELY(!is_matched)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("part with the same offset not equal, maybe not the right index", K(ret), K(ori_data_part), KPC(part)); + } else if (OB_FAIL(used_table_to_tablet_id_map_.set_refactored(partitioned_table_id, part->get_tablet_id()))) { + LOG_WARN("fail to set refactored used table to tablet id map", K(ret), K(partitioned_table_id), K(part->get_tablet_id())); + } else if (OB_FAIL(used_table_to_tablet_id_map_.set_refactored(non_partitioned_table_id, non_partitioned_table_schema->get_tablet_id()))) { + LOG_WARN("fail to set refactored used table to tablet id map", K(ret), K(non_partitioned_table_id), K(non_partitioned_table_schema->get_tablet_id())); + } else if (OB_FAIL(exchange_partition_map_relationship_(tenant_id, + *part, + *partitioned_table_schema, + *non_partitioned_table_schema, + is_oracle_mode, + ddl_operator, + trans, + schema_guard))) { + LOG_WARN("fail to exchange partition map relationship", K(ret), K(tenant_id), KPC(part), KPC(partitioned_table_schema), KPC(non_partitioned_table_schema), K(is_oracle_mode)); + } + } + } + } + return ret; +} + +int ObPartitionExchange::exchange_auxiliary_table_subpartition_(const uint64_t tenant_id, + const int64_t ori_data_partition_index, + const int64_t ori_data_subpartition_index, + const ObPartition &ori_data_part, + const ObSubPartition &ori_data_subpart, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + const ObPartition *part = nullptr; + const ObSubPartition *subpart = nullptr; + const ObTableSchema *partitioned_table_schema = NULL; + const ObTableSchema *non_partitioned_table_schema = NULL; + bool is_matched = false; + ObCheckPartitionMode check_partition_mode = CHECK_PARTITION_MODE_NORMAL; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_INDEX == ori_data_partition_index || + OB_INVALID_INDEX == ori_data_subpartition_index || !ori_data_part.is_valid() || !ori_data_subpart.is_valid() || !used_table_to_tablet_id_map_.created())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(ori_data_partition_index), K(ori_data_subpartition_index), K(ori_data_part.is_valid()), K(ori_data_subpart.is_valid()), K(used_table_to_tablet_id_map_.created())); + } else { + common::hash::ObHashMap::iterator iter; + for (iter = used_pt_nt_id_map_.begin(); OB_SUCC(ret) && iter != used_pt_nt_id_map_.end(); ++iter) { + uint64_t partitioned_table_id = iter->first; + uint64_t non_partitioned_table_id = iter->second; + if (OB_FAIL(schema_guard.get_table_schema(tenant_id, partitioned_table_id, partitioned_table_schema))) { + LOG_WARN("get table schema failed", K(ret), K(tenant_id), K(partitioned_table_id)); + } else if (OB_ISNULL(partitioned_table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema should not be null", K(ret), K(tenant_id), K(partitioned_table_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, non_partitioned_table_id, non_partitioned_table_schema))) { + LOG_WARN("get table schema failed", K(ret), K(tenant_id), K(non_partitioned_table_id)); + } else if (OB_ISNULL(non_partitioned_table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema should not be null", K(ret), K(tenant_id), K(non_partitioned_table_id)); + } else { + const schema::ObPartitionOption &pt_part_option = partitioned_table_schema->get_part_option(); + schema::ObPartitionFuncType pt_part_func_type = pt_part_option.get_part_func_type(); + const schema::ObPartitionOption &pt_subpart_option = partitioned_table_schema->get_sub_part_option(); + schema::ObPartitionFuncType pt_subpart_func_type = pt_subpart_option.get_sub_part_func_type(); + if (OB_FAIL(partitioned_table_schema->get_partition_by_partition_index(ori_data_partition_index, check_partition_mode, part))) { + LOG_WARN("get_partition_by_partition_index fail", K(ret), K(ori_data_partition_index), KPC(partitioned_table_schema)); + } else if (OB_ISNULL(part)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("partition not found", K(ret), K(ori_data_partition_index), KPC(partitioned_table_schema)); + } else if (OB_FAIL(ddl_service_.check_same_partition(is_oracle_mode, ori_data_part, *part, pt_part_func_type, is_matched))) { + LOG_WARN("fail to check ori_table_part and ori_aux_part is the same", K(ret), K(is_oracle_mode), K(ori_data_part), KPC(part), K(pt_part_func_type)); + } else if (!is_matched) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("part with the same offset not equal, maybe not the right index", K(ret), K(ori_data_part), KPC(part)); + } else if (OB_FAIL(part->get_normal_subpartition_by_subpartition_index(ori_data_subpartition_index, subpart))) { + LOG_WARN("fail to get src subpart by subpart index", K(ret), K(ori_data_subpartition_index)); + } else if (OB_ISNULL(subpart)) { + ret = OB_PARTITION_NOT_EXIST; + LOG_WARN("partition not found", K(ret), K(part), K(ori_data_subpartition_index), KPC(partitioned_table_schema)); + } else if (OB_FAIL(ddl_service_.check_same_subpartition(is_oracle_mode, ori_data_subpart, *subpart, pt_subpart_func_type, is_matched))) { + LOG_WARN("fail to check ori_table_subpart and ori_aux_subpart is the same", K(ret), K(is_oracle_mode), K(ori_data_subpart), KPC(subpart), K(pt_subpart_func_type)); + } else if (!is_matched) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("part with the same offset not equal, maybe not the right index", K(ret), K(ori_data_subpart), KPC(subpart)); + } else if (OB_FAIL(used_table_to_tablet_id_map_.set_refactored(partitioned_table_id, subpart->get_tablet_id()))) { + LOG_WARN("fail to set refactored used table to tablet id map", K(ret), K(partitioned_table_id), K(subpart->get_tablet_id())); + } else if (OB_FAIL(used_table_to_tablet_id_map_.set_refactored(non_partitioned_table_id, non_partitioned_table_schema->get_tablet_id()))) { + LOG_WARN("fail to set refactored used table to tablet id map", K(ret), K(non_partitioned_table_id), K(non_partitioned_table_schema->get_tablet_id())); + } else if (OB_FAIL(exchange_subpartition_map_relationship_(tenant_id, + *part, + *subpart, + *partitioned_table_schema, + *non_partitioned_table_schema, + is_oracle_mode, + ddl_operator, + trans, + schema_guard))) { + LOG_WARN("fail to exchange subpartition map relationship", K(ret), K(tenant_id), KPC(part), KPC(subpart), KPC(partitioned_table_schema), KPC(non_partitioned_table_schema), K(is_oracle_mode)); + } + } + } + } + return ret; +} + +int ObPartitionExchange::exchange_partition_map_relationship_(const uint64_t tenant_id, + const ObPartition &part, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + ObArray exchange_table_ids; + ObArray exchange_tablet_ids; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || !part.is_valid() || !partitioned_table_schema.is_valid() || !non_partitioned_table_schema.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(part), K(partitioned_table_schema.is_valid()), K(non_partitioned_table_schema.is_valid())); + } else if (OB_FAIL(exchange_table_ids.push_back(non_partitioned_table_schema.get_table_id()))) { + LOG_WARN("fail to push back table id", K(ret), K(non_partitioned_table_schema.get_table_id()), K(exchange_table_ids), K(non_partitioned_table_schema)); + } else if (OB_FAIL(exchange_table_ids.push_back(partitioned_table_schema.get_table_id()))) { + LOG_WARN("fail to push back table id", K(ret), K(partitioned_table_schema.get_table_id()), K(exchange_table_ids), K(partitioned_table_schema)); + } else if (OB_FAIL(exchange_tablet_ids.push_back(part.get_tablet_id()))) { + LOG_WARN("fail to push back partitioned table tablet id", K(ret), K(part.get_tablet_id())); + } else if (OB_FAIL(exchange_tablet_ids.push_back(non_partitioned_table_schema.get_tablet_id()))) { + LOG_WARN("fail to push back non_partitioned table tablet id", K(ret), K(non_partitioned_table_schema.get_tablet_id())); + } else if (OB_UNLIKELY(2 != exchange_table_ids.count() || 2 != exchange_tablet_ids.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("the array length is incorrect", K(ret), K(exchange_table_ids.count()), K(exchange_tablet_ids.count())); + } else { + // drop exchange partition in partitioned table, and add new exchange partition in partitioned table + HEAP_VARS_3((ObPartition, new_part), + (ObTableSchema, new_nt_schema), + (AlterTableSchema, alter_pt_drop_part_schema)) { + if (OB_FAIL(new_part.assign(part))) { + LOG_WARN("fail to assign part", K(ret), K(part)); + } else if (OB_FAIL(alter_pt_drop_part_schema.assign(partitioned_table_schema))) { + LOG_WARN("fail to assign partitioned table schema", K(ret), K(partitioned_table_schema)); + } else if (FALSE_IT(alter_pt_drop_part_schema.reset_partition_schema())) { + } else if (OB_FAIL(alter_pt_drop_part_schema.add_partition(part))) { + LOG_WARN("fail to add partition", K(ret), K(part)); + } else if (FALSE_IT(alter_pt_drop_part_schema.set_part_level(partitioned_table_schema.get_part_level()))) { + } else if (OB_FAIL(alter_pt_drop_part_schema.get_part_option().assign(partitioned_table_schema.get_part_option()))) { + LOG_WARN("fail to assign part option", K(ret), K(partitioned_table_schema.get_part_option())); + } else if (FALSE_IT(alter_pt_drop_part_schema.get_part_option().set_part_num(alter_pt_drop_part_schema.get_partition_num()))) { + } else if (OB_FAIL(new_nt_schema.assign(non_partitioned_table_schema))) { + LOG_WARN("fail to assign non_partitioned table schema", K(ret), K(non_partitioned_table_schema)); + } else { + new_part.set_tablet_id(exchange_tablet_ids.at(1)); + new_nt_schema.set_tablet_id(exchange_tablet_ids.at(0)); + HEAP_VARS_2((ObTableSchema, new_pt_schema), + (AlterTableSchema, alter_pt_add_new_part_schema)) { + int64_t new_partition_id = OB_INVALID_PARTITION_ID; + if (OB_FAIL(new_pt_schema.assign(partitioned_table_schema))) { + LOG_WARN("fail to assign partitioned table schema", K(ret), K(partitioned_table_schema)); + } else if (OB_FAIL(alter_pt_add_new_part_schema.assign(partitioned_table_schema))) { + LOG_WARN("fail to assign partitioned table schema", K(ret), K(partitioned_table_schema)); + } else if (FALSE_IT(alter_pt_add_new_part_schema.reset_partition_schema())) { + } else if (OB_FAIL(alter_pt_add_new_part_schema.add_partition(new_part))) { + LOG_WARN("fail to add partition", K(ret), K(new_part)); + } else if (FALSE_IT(alter_pt_add_new_part_schema.set_part_level(partitioned_table_schema.get_part_level()))) { + } else if (OB_FAIL(alter_pt_add_new_part_schema.get_part_option().assign(partitioned_table_schema.get_part_option()))) { + LOG_WARN("fail to assign part option", K(ret), K(partitioned_table_schema.get_part_option())); + } else if (FALSE_IT(alter_pt_add_new_part_schema.get_part_option().set_part_num(alter_pt_add_new_part_schema.get_partition_num()))) { + } else if (OB_FAIL(ddl_service_.generate_object_id_for_partition_schema(alter_pt_add_new_part_schema))) { + LOG_WARN("fail to generate object_id for partition schema", K(ret), K(alter_pt_add_new_part_schema)); + } else if (OB_FAIL(get_object_id_from_partition_schema_(alter_pt_add_new_part_schema, false/*get_subpart_only*/, new_partition_id))) { + LOG_WARN("fail get object id from partition schema", K(ret), K(alter_pt_add_new_part_schema), K(new_partition_id)); + } else if (OB_FAIL(update_exchange_table_non_schema_attributes_(tenant_id, + part.get_part_id(), + new_partition_id, + false/*is_exchange_subpartition*/, + new_pt_schema, + new_nt_schema, + exchange_table_ids, + exchange_tablet_ids, + is_oracle_mode, + ddl_operator, + trans, + schema_guard))) { + LOG_WARN("fail to update exchange table non schema attributes", K(ret), K(part.get_part_id()), K(new_partition_id), K(new_pt_schema), K(new_nt_schema), K(exchange_table_ids), K(exchange_tablet_ids), K(is_oracle_mode)); + } else if (OB_FAIL(ddl_operator.exchange_table_partitions(partitioned_table_schema, + alter_pt_add_new_part_schema, + alter_pt_drop_part_schema, + trans))) { + LOG_WARN("failed to exchange partitions", K(ret), K(partitioned_table_schema), K(alter_pt_add_new_part_schema), K(alter_pt_drop_part_schema)); + } else if (OB_FAIL(update_exchange_table_level_attributes_(tenant_id, + exchange_table_ids, + exchange_tablet_ids, + new_pt_schema, + new_nt_schema, + trans))) { + LOG_WARN("fail to update exchange table level attributes", K(ret), K(tenant_id), K(exchange_table_ids), K(exchange_tablet_ids), K(new_pt_schema), K(new_nt_schema)); + } + } + } + } + } + return ret; +} + +int ObPartitionExchange::exchange_subpartition_map_relationship_(const uint64_t tenant_id, + const ObPartition &part, + const ObSubPartition &subpart, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + ObArray exchange_table_ids; + ObArray exchange_tablet_ids; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || !part.is_valid() || !subpart.is_valid() || !partitioned_table_schema.is_valid() || !non_partitioned_table_schema.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(part), K(subpart), K(partitioned_table_schema.is_valid()), K(non_partitioned_table_schema.is_valid())); + } else if (OB_FAIL(exchange_table_ids.push_back(non_partitioned_table_schema.get_table_id()))) { + LOG_WARN("fail to push back table id", K(ret), K(non_partitioned_table_schema.get_table_id()), K(exchange_table_ids), K(non_partitioned_table_schema)); + } else if (OB_FAIL(exchange_table_ids.push_back(partitioned_table_schema.get_table_id()))) { + LOG_WARN("fail to push back table id", K(ret), K(partitioned_table_schema.get_table_id()), K(exchange_table_ids), K(partitioned_table_schema)); + } else if (OB_FAIL(exchange_tablet_ids.push_back(subpart.get_tablet_id()))) { + LOG_WARN("fail to push back partitioned table tablet id", K(ret), K(subpart.get_tablet_id())); + } else if (OB_FAIL(exchange_tablet_ids.push_back(non_partitioned_table_schema.get_tablet_id()))) { + LOG_WARN("fail to push back non_partitioned table tablet id", K(ret), K(non_partitioned_table_schema.get_table_id())); + } else if (OB_UNLIKELY(2 != exchange_table_ids.count() || 2 != exchange_tablet_ids.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("the array length is incorrect", K(ret), K(exchange_table_ids.count()), K(exchange_tablet_ids.count())); + } else { + // drop exchange subpartition in partitioned table, and add new exchange subpartition in partitioned table + HEAP_VARS_4((ObSubPartition, new_subpart), + (ObPartition, dummy_part), + (ObTableSchema, new_nt_schema), + (AlterTableSchema, alter_pt_drop_subpart_schema)) { + dummy_part.set_sub_part_num(1); + dummy_part.set_part_id(part.get_part_id()); + if (OB_FAIL(new_subpart.assign(subpart))) { + LOG_WARN("fail to assign subpartition schema", K(ret), K(subpart)); + } else if (OB_FAIL(dummy_part.set_part_name(part.get_part_name()))) { + LOG_WARN("failed to set part name", K(ret), K(part.get_part_name())); + } else if (OB_FAIL(dummy_part.add_partition(subpart))){ + LOG_WARN("failed to add subpart", K(ret), K(subpart)); + } else if (OB_FAIL(alter_pt_drop_subpart_schema.assign(partitioned_table_schema))) { + LOG_WARN("fail to assign partitioned table schema", K(ret), K(partitioned_table_schema)); + } else if (FALSE_IT(alter_pt_drop_subpart_schema.reset_partition_schema())) { + } else if (OB_FAIL(alter_pt_drop_subpart_schema.add_partition(dummy_part))) { + LOG_WARN("failed to add partition", K(ret), K(dummy_part)); + } else if (FALSE_IT(alter_pt_drop_subpart_schema.set_part_level(partitioned_table_schema.get_part_level()))) { + } else if (OB_FAIL(alter_pt_drop_subpart_schema.get_part_option().assign(partitioned_table_schema.get_part_option()))) { + LOG_WARN("fail to assign part option", K(ret), K(partitioned_table_schema.get_part_option())); + } else if (OB_FAIL(alter_pt_drop_subpart_schema.get_sub_part_option().assign(partitioned_table_schema.get_sub_part_option()))) { + LOG_WARN("fail to assign subpart option", K(ret), K(partitioned_table_schema.get_sub_part_option())); + } else if (FALSE_IT(alter_pt_drop_subpart_schema.get_part_option().set_part_num(alter_pt_drop_subpart_schema.get_partition_num()))) { + } else if (OB_FAIL(new_nt_schema.assign(non_partitioned_table_schema))) { + LOG_WARN("fail to assign non_partitioned table schema", K(ret), K(non_partitioned_table_schema)); + } else { + new_subpart.set_tablet_id(exchange_tablet_ids.at(1)); + new_nt_schema.set_tablet_id(exchange_tablet_ids.at(0)); + HEAP_VARS_2((ObTableSchema, new_pt_schema), + (AlterTableSchema, alter_pt_add_new_subpart_schema)) { + dummy_part.reset(); + dummy_part.set_sub_part_num(1); + dummy_part.set_part_id(part.get_part_id()); + int64_t new_subpart_id = OB_INVALID_PARTITION_ID; + if (OB_FAIL(new_pt_schema.assign(partitioned_table_schema))) { + LOG_WARN("fail to assign partitioned table schema", K(ret), K(partitioned_table_schema)); + } else if (OB_FAIL(dummy_part.set_part_name(part.get_part_name()))) { + LOG_WARN("failed to set part name", K(ret), K(part.get_part_name())); + } else if (OB_FAIL(dummy_part.add_partition(new_subpart))){ + LOG_WARN("failed to add subpart", K(ret), K(new_subpart)); + } else if (OB_FAIL(alter_pt_add_new_subpart_schema.assign(partitioned_table_schema))) { + LOG_WARN("fail to assign partitioned table schema", K(ret), K(partitioned_table_schema)); + } else if (FALSE_IT(alter_pt_add_new_subpart_schema.reset_partition_schema())) { + } else if (FALSE_IT(alter_pt_add_new_subpart_schema.set_part_level(partitioned_table_schema.get_part_level()))) { + } else if (OB_FAIL(alter_pt_add_new_subpart_schema.get_sub_part_option().assign(partitioned_table_schema.get_sub_part_option()))) { + LOG_WARN("fail to assign subpart option", K(ret), K(partitioned_table_schema.get_sub_part_option())); + } else if (OB_FAIL(alter_pt_add_new_subpart_schema.add_partition(dummy_part))) { + LOG_WARN("fail to add subpartition", K(ret), K(dummy_part)); + } else if (OB_FAIL(alter_pt_add_new_subpart_schema.get_part_option().assign(partitioned_table_schema.get_part_option()))) { + LOG_WARN("fail to assign subpart option", K(ret), K(partitioned_table_schema.get_part_option())); + } else if (FALSE_IT(alter_pt_add_new_subpart_schema.set_part_num(alter_pt_add_new_subpart_schema.get_partition_num()))) { + } else if (OB_FAIL(ddl_service_.generate_object_id_for_partition_schema(alter_pt_add_new_subpart_schema, true/*gen_subpart_only*/))) { + LOG_WARN("fail to generate object_id for partition schema", K(ret), K(alter_pt_add_new_subpart_schema)); + } else if (OB_FAIL(get_object_id_from_partition_schema_(alter_pt_add_new_subpart_schema, true/*gen_subpart_only*/, new_subpart_id))) { + LOG_WARN("fail get object id from partition schema", K(ret), K(alter_pt_add_new_subpart_schema), K(new_subpart_id)); + } else if (OB_FAIL(update_exchange_table_non_schema_attributes_(tenant_id, + subpart.get_sub_part_id(), + new_subpart_id, + true/*is_exchange_subpartition*/, + new_pt_schema, + new_nt_schema, + exchange_table_ids, + exchange_tablet_ids, + is_oracle_mode, + ddl_operator, + trans, + schema_guard))) { + LOG_WARN("fail update exchange table non schema attributes", K(ret), K(subpart.get_sub_part_id()), K(new_subpart_id), K(new_pt_schema), K(new_nt_schema), K(exchange_table_ids), K(exchange_tablet_ids), K(is_oracle_mode)); + } else if (OB_FAIL(ddl_operator.exchange_table_subpartitions(partitioned_table_schema, + alter_pt_add_new_subpart_schema, + alter_pt_drop_subpart_schema, + trans))) { + LOG_WARN("failed to exchange subpartitions", K(ret), K(partitioned_table_schema), K(alter_pt_add_new_subpart_schema), K(alter_pt_drop_subpart_schema)); + } else if (OB_FAIL(update_exchange_table_level_attributes_(tenant_id, + exchange_table_ids, + exchange_tablet_ids, + new_pt_schema, + new_nt_schema, + trans))) { + LOG_WARN("fail to update exchange table level attributes", K(ret), K(tenant_id), K(exchange_table_ids), K(exchange_tablet_ids), K(new_pt_schema), K(new_nt_schema)); + } + } + } + } + } + return ret; +} + +int ObPartitionExchange::update_exchange_table_non_schema_attributes_(const uint64_t tenant_id, + const int64_t old_partition_id, + const int64_t new_partition_id, + const bool is_exchange_subpartition, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const ObIArray &exchange_table_ids, + const ObIArray &exchange_tablet_ids, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == old_partition_id || OB_INVALID_ID == new_partition_id || exchange_table_ids.count() != exchange_tablet_ids.count() || 2 != exchange_table_ids.count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(old_partition_id), K(new_partition_id), K(partitioned_table_schema), K(non_partitioned_table_schema), K(exchange_table_ids), K(exchange_tablet_ids)); + } else { + // modify inner table __all_tablet_to_ls, __all_sequence_value or __all_sequence_value, __all_table_stat, __all_column_stat, __all_histogram_stat, __all_monitor_modified + if (OB_SUCC(ret)) { + if (OB_FAIL(update_table_to_tablet_id_mapping_(tenant_id, exchange_table_ids, exchange_tablet_ids, trans))) { + LOG_WARN("fail to update table to tablet id mapping", K(ret), K(tenant_id), K(exchange_table_ids), K(exchange_tablet_ids)); + } else if (!partitioned_table_schema.is_aux_table() && !non_partitioned_table_schema.is_aux_table()) { + // TODO: After confirming the specific behavior of self increasing columns in MySQL mode and identity in Oracle mode, supplement it. + // if (is_oracle_mode) { + // if (OB_FAIL(update_identity_column_information_(tenant_id, partitioned_table_schema, non_partitioned_table_schema, is_oracle_mode, ddl_operator, trans, schema_guard))) { + // LOG_WARN("failed to update identity column information", K(ret), K(tenant_id), K(partitioned_table_schema), K(non_partitioned_table_schema), K(is_oracle_mode)); + // } + // } else if (OB_FAIL(update_autoinc_column_information_(tenant_id, partitioned_table_schema, non_partitioned_table_schema, ddl_operator, trans))) { + // LOG_WARN("failed to update autoinc column information", K(ret), K(tenant_id), K(partitioned_table_schema), K(non_partitioned_table_schema)); + // } + if (OB_SUCC(ret)) { + if (!is_exchange_subpartition) { + if (OB_FAIL(sync_exchange_partition_stats_info_(tenant_id, + partitioned_table_schema.get_table_id(), + StatLevel::PARTITION_LEVEL, + non_partitioned_table_schema.get_table_id(), + new_partition_id, + exchange_tablet_ids.at(1), + non_partitioned_table_schema, + trans))) { + LOG_WARN("fail to sync exchange partition stats info", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schema), K(new_partition_id), K(exchange_tablet_ids)); + } + } else if (OB_FAIL(sync_exchange_partition_stats_info_(tenant_id, + partitioned_table_schema.get_table_id(), + StatLevel::SUBPARTITION_LEVEL, + non_partitioned_table_schema.get_table_id(), + new_partition_id, + exchange_tablet_ids.at(1), + non_partitioned_table_schema, + trans))) { + LOG_WARN("fail to sync exchange subpartition stats info", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schema), K(new_partition_id), K(exchange_tablet_ids)); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(sync_exchange_partition_stats_info_(tenant_id, + non_partitioned_table_schema.get_table_id(), + StatLevel::TABLE_LEVEL, + old_partition_id, + non_partitioned_table_schema.get_table_id(), + exchange_tablet_ids.at(0), + partitioned_table_schema, + trans))) { + LOG_WARN("fail to sync exchange partition stats info", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schema), K(old_partition_id), K(exchange_tablet_ids)); + } + } + } + } + } + } + return ret; +} + +int ObPartitionExchange::update_exchange_table_level_attributes_(const uint64_t tenant_id, + const ObIArray &exchange_table_ids, + const ObIArray &exchange_tablet_ids, + ObTableSchema &partitioned_table_schema, + ObTableSchema &non_partitioned_table_schema, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + ObArray pt_tablet_ids; + ObArray nt_tablet_ids; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || 2 != exchange_table_ids.count() || 2 != exchange_tablet_ids.count() || !partitioned_table_schema.is_valid() || !non_partitioned_table_schema.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(exchange_table_ids.count()), K(exchange_tablet_ids.count()), K(partitioned_table_schema.is_valid()), K(non_partitioned_table_schema.is_valid())); + } else if (OB_FAIL(nt_tablet_ids.push_back(exchange_tablet_ids.at(0)))) { + LOG_WARN("failed to push back tablet id", K(ret), K(exchange_tablet_ids.at(0))); + } else if (OB_FAIL(pt_tablet_ids.push_back(exchange_tablet_ids.at(1)))) { + LOG_WARN("failed to push back tablet id", K(ret), K(exchange_tablet_ids.at(1))); + } else { + // modify inner table __all_tablet_to_table_history and __all_table + share::ObTabletTablePair pair; + ObArray pt_pairs; + ObArray nt_pairs; + for (int64_t i = 0; OB_SUCC(ret) && i < exchange_tablet_ids.count(); i++) { + if (OB_FAIL(pair.init(exchange_tablet_ids.at(i), exchange_table_ids.at(i)))) { + LOG_WARN("fail to init tablet to table pair", K(ret), K(exchange_tablet_ids.at(i)), K(exchange_table_ids.at(i))); + } else if (exchange_table_ids.at(i) == partitioned_table_schema.get_table_id()) { + if (OB_FAIL(pt_pairs.push_back(pair))) { + LOG_WARN("fail to push back tablet table pair", K(ret), K(pair), K(pt_pairs)); + } + } else if (exchange_table_ids.at(i) == non_partitioned_table_schema.get_table_id()) { + if (OB_FAIL(nt_pairs.push_back(pair))) { + LOG_WARN("fail to push back tablet table pair", K(ret), K(pair), K(nt_pairs)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exchange table id is error", K(ret), K(exchange_table_ids.at(i)), K(partitioned_table_schema.get_table_id()), K(non_partitioned_table_schema.get_table_id())); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(refresh_table_schema_version_(tenant_id, non_partitioned_table_schema))) { + LOG_WARN("fail to refresh table schema version", K(ret), K(non_partitioned_table_schema)); + } else if (OB_FAIL(refresh_table_schema_version_(tenant_id, partitioned_table_schema))) { + LOG_WARN("fail to refresh table schema version", K(ret), K(partitioned_table_schema)); + } else if (OB_FAIL(ObTabletToTableHistoryOperator::create_tablet_to_table_history(trans, tenant_id, partitioned_table_schema.get_schema_version(), pt_pairs))) { + LOG_WARN("fail to create tablet to table history", K(ret), K(tenant_id), K(partitioned_table_schema)); + } else if (OB_FAIL(ObTabletToTableHistoryOperator::create_tablet_to_table_history(trans, tenant_id, non_partitioned_table_schema.get_schema_version(), nt_pairs))) { + LOG_WARN("fail to create tablet to table history", K(ret), K(tenant_id), K(non_partitioned_table_schema)); + } else if (OB_FAIL(update_table_attribute_(non_partitioned_table_schema, trans))) { + LOG_WARN("fail to update table attribute", K(ret), K(non_partitioned_table_schema)); + } else if (OB_FAIL(update_table_attribute_(partitioned_table_schema, trans))) { + LOG_WARN("fail to update table attribute", K(ret), K(partitioned_table_schema)); + } else if (partitioned_table_schema.is_aux_table() && non_partitioned_table_schema.is_aux_table()) { + if (OB_FAIL(build_single_table_rw_defensive_(tenant_id, nt_tablet_ids, non_partitioned_table_schema.get_schema_version(), trans))) { + LOG_WARN("failed to build rw defensive", K(ret), K(tenant_id), K(nt_tablet_ids), K(non_partitioned_table_schema.get_schema_version())); + } else if (OB_FAIL(build_single_table_rw_defensive_(tenant_id, pt_tablet_ids, partitioned_table_schema.get_schema_version(), trans))) { + LOG_WARN("failed to build rw defensive", K(ret), K(tenant_id), K(pt_tablet_ids), K(partitioned_table_schema.get_schema_version())); + } + } + } + } + return ret; +} + +int ObPartitionExchange::update_table_to_tablet_id_mapping_(const uint64_t tenant_id, + const ObIArray &table_ids, + const ObIArray &tablet_ids, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id) || table_ids.count() != tablet_ids.count() || 2 != table_ids.count()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(table_ids.count()), K(tablet_ids.count())); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < table_ids.count(); i++) { + if (OB_FAIL(ObTabletToLSTableOperator::update_table_to_tablet_id_mapping(trans, tenant_id, table_ids.at(i), tablet_ids.at(i)))) { + LOG_WARN("fail to update table to tablet id mapping", K(ret), K(tenant_id), K(table_ids.at(i)), K(tablet_ids.at(i))); + } + } + } + return ret; +} + +int ObPartitionExchange::refresh_table_schema_version_(const uint64_t tenant_id, ObTableSchema &table_schema) +{ + int ret = OB_SUCCESS; + int64_t new_schema_version = OB_INVALID_VERSION; + ObMultiVersionSchemaService &multi_schema_service = ddl_service_.get_schema_service(); + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id)); + } else if (OB_FAIL(multi_schema_service.gen_new_schema_version(tenant_id, new_schema_version))) { + LOG_WARN("fail to gen new schema_version", K(ret), K(tenant_id)); + } else { + table_schema.set_schema_version(new_schema_version); + } + return ret; +} + +int ObPartitionExchange::update_table_attribute_(const ObTableSchema &table_schema, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + ObSchemaService *schema_service = NULL; + ObSchemaOperationType operation_type = OB_DDL_EXCHANGE_PARTITION; + ObMultiVersionSchemaService &multi_schema_service = ddl_service_.get_schema_service(); + if (OB_ISNULL(schema_service = multi_schema_service.get_schema_service())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get schema_service is null", K(ret)); + } else if (OB_FAIL(schema_service->get_table_sql_service().update_table_attribute(trans, + table_schema, + operation_type, + false/*update_object_status_ignore_version*/, + nullptr/*ddl_stmt_str*/))) { + LOG_WARN("failed to update table schema attribute", K(ret), K(table_schema), K(operation_type)); + } + return ret; +} + +int ObPartitionExchange::push_data_table_schema_version_(const uint64_t tenant_id, + const ObTableSchema &table_schema, + const common::ObString *ddl_stmt_str, + const uint64_t exchange_data_table_id, + int64_t &new_schema_version, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + ObTabletID tablet_id; + ObArray tablet_ids; + ObSchemaOperationType operation_type = OB_DDL_EXCHANGE_PARTITION; + ObSchemaService *schema_service = NULL; + ObMultiVersionSchemaService &multi_schema_service = ddl_service_.get_schema_service(); + new_schema_version = OB_INVALID_VERSION; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == exchange_data_table_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(exchange_data_table_id)); + } else if (OB_FAIL(used_table_to_tablet_id_map_.get_refactored(exchange_data_table_id, tablet_id))) { + LOG_WARN("get_refactored tablet id from used_table_to_tablet_id_map failed", K(ret), K(exchange_data_table_id)); + } else if (OB_FAIL(tablet_ids.push_back(tablet_id))) { + LOG_WARN("failed to push back tablet id", K(ret), K(tablet_id)); + } else if (OB_ISNULL(schema_service = multi_schema_service.get_schema_service())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get schema_service is null", K(ret)); + } else { + ObRefreshSchemaStatus schema_status; + schema_status.tenant_id_ = tenant_id; + HEAP_VAR(ObTableSchema, new_table_schema) { + if (OB_FAIL(schema_service->get_table_schema_from_inner_table(schema_status, table_schema.get_table_id(), trans, new_table_schema))) { + LOG_WARN("get_table_schema failed", K(ret), K(schema_status), K(table_schema.get_table_id())); + } else if (OB_FAIL(refresh_table_schema_version_(tenant_id, new_table_schema))) { + LOG_WARN("fail to refresh table schema version", K(ret), K(new_table_schema)); + } else if (OB_FAIL(schema_service->get_table_sql_service().update_table_schema_version(trans, + new_table_schema, + operation_type, + ddl_stmt_str))) { + LOG_WARN("failed to update table schema version", K(ret), K(new_table_schema), K(operation_type)); + } else if (OB_FAIL(build_single_table_rw_defensive_(tenant_id, tablet_ids, new_table_schema.get_schema_version(), trans))) { + LOG_WARN("failed to build rw defensive", K(ret), K(tenant_id), K(tablet_ids), K(new_table_schema.get_schema_version())); + } else { + new_schema_version = new_table_schema.get_schema_version(); + } + } + } + return ret; +} + +int ObPartitionExchange::get_local_storage_index_and_lob_table_schemas_(const ObTableSchema &table_schema, + const bool is_pt_schema, + const bool is_oracle_mode, + ObIArray &table_schemas, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + ObSEArray simple_index_infos; + ObSEArray aux_table_ids; + table_schemas.reset(); + if (OB_FAIL(!table_schema.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(table_schema), K(table_schema.is_valid())); + } else if (OB_FAIL(table_schema.get_simple_index_infos(simple_index_infos))) { + LOG_WARN("get simple index infos failed", K(ret)); + } else { + const uint64_t tenant_id = table_schema.get_tenant_id(); + for (int64_t i = 0; OB_SUCC(ret) && i < simple_index_infos.count(); i++) { + if (OB_FAIL(aux_table_ids.push_back(simple_index_infos.at(i).table_id_))) { + LOG_WARN("fail to push back index table id", K(ret), K(simple_index_infos.at(i).table_id_)); + } + } + if (OB_SUCC(ret)) { + uint64_t mtid = table_schema.get_aux_lob_meta_tid(); + uint64_t ptid = table_schema.get_aux_lob_piece_tid(); + if (!((mtid != OB_INVALID_ID && ptid != OB_INVALID_ID) || (mtid == OB_INVALID_ID && ptid == OB_INVALID_ID))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Expect meta tid and piece tid both valid or both invalid", K(ret), K(mtid), K(ptid)); + } else if (OB_INVALID_ID != mtid && OB_FAIL(aux_table_ids.push_back(mtid))) { + LOG_WARN("fail to push back lob meta tid", K(ret), K(mtid)); + } else if (OB_INVALID_ID != ptid && OB_FAIL(aux_table_ids.push_back(ptid))) { + LOG_WARN("fail to push back lob piece tid", K(ret), K(ptid)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < aux_table_ids.count(); i++) { + const ObTableSchema *aux_table_schema = NULL; + if (OB_FAIL(schema_guard.get_table_schema(tenant_id, aux_table_ids.at(i), aux_table_schema))) { + LOG_WARN("get table schema failed", K(ret), K(tenant_id), K(aux_table_ids.at(i))); + } else if (OB_ISNULL(aux_table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema should not be null", K(ret)); + } else if (OB_FAIL(check_auxiliary_schema_conditions_(aux_table_schema, is_oracle_mode))) { + LOG_WARN("fail to check auxiliary schema conditions", K(ret), K(aux_table_schema), K(is_oracle_mode)); + } else if (aux_table_schema->is_index_table() && aux_table_schema->is_global_index_table()) { + if (is_pt_schema) { + if (OB_FAIL(unused_pt_index_id_.push_back(aux_table_schema->get_table_id()))) { + LOG_WARN("failed to push back", K(ret), K(aux_table_schema->get_table_id())); + } + } else if (OB_FAIL(unused_nt_index_id_.push_back(aux_table_schema->get_table_id()))) { + LOG_WARN("failed to push back", K(ret), K(aux_table_schema->get_table_id())); + } + } else if (OB_FAIL(table_schemas.push_back(aux_table_schema))) { + LOG_WARN("failed to push back table schema", K(ret), K(aux_table_schema)); + } + } + } + } + } + return ret; +} + +int ObPartitionExchange::check_auxiliary_schema_conditions_(const ObTableSchema *table_schema, const bool is_oracle_mode) +{ + int ret = OB_SUCCESS; + if (!table_schema->is_index_table() && !table_schema->is_aux_lob_table()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table is not index table or lob table", K(ret), K(table_schema->is_index_table()), K(table_schema->is_aux_lob_table())); + } else if (OB_UNLIKELY(table_schema->is_index_table() && table_schema->is_index_local_storage() && INDEX_STATUS_AVAILABLE != table_schema->get_index_status())) { + if (is_oracle_mode) { + ret = OB_ERR_INDEX_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("there are unavailable index table", K(ret), K(table_schema->is_index_table()), K(table_schema->get_table_id()), K(table_schema->get_index_status())); + } + return ret; +} +// it is required that the data and order of extended_type_info to be exactly the same in the mysql mode +int ObPartitionExchange::compare_column_extended_type_info_(const common::ObIArray &l_extended_type_info, const common::ObIArray &r_extended_type_info, bool &is_equal) +{ + int ret = OB_SUCCESS; + is_equal = true; + if (OB_UNLIKELY(l_extended_type_info.count() != r_extended_type_info.count())) { + is_equal = false; + LOG_WARN("column extended type info count of exchanging partition tables are not equal", K(ret), K(l_extended_type_info.count()), K(r_extended_type_info.count())); + } else { + for (int64_t i = 0; OB_SUCC(ret) && is_equal && i < l_extended_type_info.count(); i++) { + if (0 != l_extended_type_info.at(i).compare(r_extended_type_info.at(i))) { + is_equal = false; + LOG_WARN("column extended type info count of exchanging partition tables are not equal", K(ret), K(l_extended_type_info.at(i)), K(r_extended_type_info.at(i))); + } + } + } + return ret; +} + +bool ObPartitionExchange::in_supported_table_type_white_list_(const ObTableSchema &table_schema) +{ + return table_schema.is_user_table() && !table_schema.is_ctas_tmp_table(); +} + +bool ObPartitionExchange::in_find_same_aux_table_retry_white_list_(const int ret_code) +{ + return OB_ERR_PARTITION_EXCHANGE_DIFFERENT_OPTION == ret_code || + OB_ERR_COLUMNS_NUMBER_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION == ret_code || + OB_ERR_COLUMN_TYPE_OR_SIZE_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION == ret_code || + OB_ERR_FOREIGN_KEY_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION == ret_code || + OB_ERR_INDEX_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION == ret_code || + OB_TABLES_DIFFERENT_DEFINITIONS == ret_code; +} + +int ObPartitionExchange::generate_auxiliary_table_mapping_(const ObTableSchema &partitioned_data_table_schema, + const ObTableSchema &non_partitioned_data_table_schema, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + const bool is_oracle_mode, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + ObArray partitioned_table_schemas; + ObArray non_partitioned_table_schemas; + ObArray used_nt_schema_flag; + bool is_equal = false; + if (OB_UNLIKELY(!used_pt_nt_id_map_.created() || exchange_partition_name.empty() || PARTITION_LEVEL_ZERO == exchange_partition_level)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(used_pt_nt_id_map_.created()), K(exchange_partition_name), K(exchange_partition_level)); + } else if (OB_FAIL(get_local_storage_index_and_lob_table_schemas_(partitioned_data_table_schema, true/*is_partitioned_table_schema*/, is_oracle_mode, partitioned_table_schemas, schema_guard))) { + LOG_WARN("fail to get local storage index and lob table schemas", K(ret), K(partitioned_data_table_schema), K(is_oracle_mode)); + } else if (OB_FAIL(get_local_storage_index_and_lob_table_schemas_(non_partitioned_data_table_schema, false/*is_partitioned_table_schema*/, is_oracle_mode, non_partitioned_table_schemas, schema_guard))) { + LOG_WARN("fail to get local storage index and lob table schemas", K(ret), K(non_partitioned_data_table_schema), K(is_oracle_mode)); + } else if (OB_UNLIKELY(partitioned_table_schemas.count() != non_partitioned_table_schemas.count())) { + if (is_oracle_mode) { + ret = OB_ERR_INDEX_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("pt schemas count and nt schemas count are not equal", K(ret), K(partitioned_table_schemas.count()), K(non_partitioned_table_schemas.count())); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < non_partitioned_table_schemas.count(); i++) { + if (OB_FAIL(used_nt_schema_flag.push_back(false))) { + LOG_WARN("failed to push back", K(ret), K(i), K(used_nt_schema_flag)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < partitioned_table_schemas.count(); i++) { + // for each partitioned table, find a one-to-one corresponding table in the non partitioned table + if (OB_FAIL(generate_local_storage_index_and_lob_table_mapping_(*partitioned_table_schemas.at(i), non_partitioned_table_schemas, exchange_partition_name, exchange_partition_level, is_oracle_mode, used_nt_schema_flag))) { + LOG_WARN("fail to generate used aux table id mapping", K(ret), KPC(partitioned_table_schemas.at(i)), K(non_partitioned_table_schemas.count()), K(exchange_partition_name), K(exchange_partition_level), K(is_oracle_mode), K(used_nt_schema_flag.count())); + } + } + } + return ret; +} + +int ObPartitionExchange::generate_local_storage_index_and_lob_table_mapping_(const ObTableSchema &partitioned_table_schema, + ObIArray &non_partitioned_table_schemas, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + const bool is_oracle_mode, + ObIArray &used_nt_schema_flag) +{ + int ret = OB_SUCCESS; + bool find_related_nt_schema = false; + if (OB_UNLIKELY((!partitioned_table_schema.is_index_local_storage() && !partitioned_table_schema.is_aux_lob_table()) || non_partitioned_table_schemas.count() != used_nt_schema_flag.count() || exchange_partition_name.empty() || PARTITION_LEVEL_ZERO == exchange_partition_level)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.count()), K(used_nt_schema_flag.count()), K(exchange_partition_name), K(exchange_partition_level)); + } else if (partitioned_table_schema.is_index_local_storage()) { + if (!is_oracle_mode) { + if (OB_FAIL(generate_local_storage_index_table_mapping_in_mysql_mode_(partitioned_table_schema, non_partitioned_table_schemas, exchange_partition_name, exchange_partition_level, used_nt_schema_flag, find_related_nt_schema))) { + LOG_WARN("fail to generate local storage index table mapping in mysql mode", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.count()), K(exchange_partition_name), K(exchange_partition_level), K(used_nt_schema_flag.count()), K(find_related_nt_schema)); + } else if (!find_related_nt_schema) { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + LOG_WARN("can't find related nt schema in mysql mode", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.count()), K(used_nt_schema_flag.count()), K(find_related_nt_schema)); + } + } else if (OB_FAIL(generate_local_storage_index_table_mapping_in_oracle_mode_(partitioned_table_schema, non_partitioned_table_schemas, exchange_partition_name, exchange_partition_level, used_nt_schema_flag, find_related_nt_schema))) { + LOG_WARN("fail to generate local storage index table mapping in oracle mode", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.count()), K(exchange_partition_name), K(exchange_partition_level), K(used_nt_schema_flag.count()), K(find_related_nt_schema)); + } else if (!find_related_nt_schema) { + ret = OB_ERR_INDEX_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + LOG_WARN("can't find related nt schema in mysql mode", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.count()), K(used_nt_schema_flag.count()), K(find_related_nt_schema)); + } + } else if (OB_FAIL(generate_lob_table_mapping_(partitioned_table_schema, non_partitioned_table_schemas, exchange_partition_name, exchange_partition_level, is_oracle_mode, used_nt_schema_flag, find_related_nt_schema))){ + LOG_WARN("fail to generate lob table mapping", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.count()), K(exchange_partition_name), K(exchange_partition_level), K(is_oracle_mode), K(used_nt_schema_flag.count()), K(find_related_nt_schema)); + } else if (!find_related_nt_schema) { + if (is_oracle_mode) { + ret = OB_ERR_INDEX_MISMATCH_ALTER_TABLE_EXCHANGE_PARTITION; + } else { + ret = OB_TABLES_DIFFERENT_DEFINITIONS; + } + LOG_WARN("can't find related nt_schema", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.count()), K(used_nt_schema_flag), K(is_oracle_mode)); + } + return ret; +} + +int ObPartitionExchange::generate_local_storage_index_table_mapping_in_mysql_mode_(const ObTableSchema &partitioned_table_schema, + ObIArray &non_partitioned_table_schemas, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + ObIArray &used_nt_schema_flag, + bool &find_related_nt_schema) +{ + int ret = OB_SUCCESS; + find_related_nt_schema = false; + if (OB_UNLIKELY(!partitioned_table_schema.is_index_local_storage() || non_partitioned_table_schemas.count() != used_nt_schema_flag.count() || exchange_partition_name.empty() || PARTITION_LEVEL_ZERO == exchange_partition_level)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(partitioned_table_schema), K(partitioned_table_schema.is_index_local_storage()), K(non_partitioned_table_schemas.count()), K(used_nt_schema_flag.count()), K(exchange_partition_name), K(exchange_partition_level)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && !find_related_nt_schema && i < non_partitioned_table_schemas.count(); i++) { + ObString pt_index_name; + ObString nt_index_name; + if (OB_ISNULL(non_partitioned_table_schemas.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema is null", K(ret)); + } else if (!non_partitioned_table_schemas.at(i)->is_index_local_storage() || used_nt_schema_flag.at(i)) { + } else if (OB_FAIL(partitioned_table_schema.get_index_name(pt_index_name))) { + LOG_WARN("fail to get index name", K(ret), K(partitioned_table_schema)); + } else if (OB_FAIL(non_partitioned_table_schemas.at(i)->get_index_name(nt_index_name))) { + LOG_WARN("fail to get index name", K(ret), KPC(non_partitioned_table_schemas.at(i))); + } else if (0 == pt_index_name.compare(nt_index_name)) { + if (OB_FAIL(check_table_conditions_in_common_(partitioned_table_schema, *non_partitioned_table_schemas.at(i), exchange_partition_name, exchange_partition_level, false /*is mysql mode*/))) { + LOG_WARN("fail to check table conditions in common", K(ret), K(partitioned_table_schema), KPC(non_partitioned_table_schemas.at(i)), K(exchange_partition_name), K(exchange_partition_level)); + } else if (OB_FAIL(check_table_all_column_conditions_(partitioned_table_schema, *non_partitioned_table_schemas.at(i), false /*is mysql mode*/))) { + LOG_WARN("fail to check table all column conditions", K(ret), K(partitioned_table_schema.get_table_id()), K(non_partitioned_table_schemas.at(i)->get_table_id())); + } else { + find_related_nt_schema = true; + used_nt_schema_flag.at(i) = true; + if (OB_FAIL(used_pt_nt_id_map_.set_refactored(partitioned_table_schema.get_table_id(), non_partitioned_table_schemas.at(i)->get_table_id()))) { + LOG_WARN("fail to set refactored pt nt schema mapping", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.at(i)->get_table_id())); + } + } + } else { + LOG_WARN("index table name are different", K(ret), K(pt_index_name), K(nt_index_name)); + } + } + } + return ret; +} + +int ObPartitionExchange::generate_local_storage_index_table_mapping_in_oracle_mode_(const ObTableSchema &partitioned_table_schema, + ObIArray &non_partitioned_table_schemas, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + ObIArray &used_nt_schema_flag, + bool &find_related_nt_schema) +{ + int ret = OB_SUCCESS; + find_related_nt_schema = false; + if (OB_UNLIKELY(!partitioned_table_schema.is_index_local_storage() || non_partitioned_table_schemas.count() != used_nt_schema_flag.count() || exchange_partition_name.empty() || PARTITION_LEVEL_ZERO == exchange_partition_level)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(partitioned_table_schema), K(partitioned_table_schema.is_index_local_storage()), K(non_partitioned_table_schemas.count()), K(used_nt_schema_flag.count()), K(exchange_partition_name), K(exchange_partition_level)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && !find_related_nt_schema && i < non_partitioned_table_schemas.count(); i++) { + if (OB_ISNULL(non_partitioned_table_schemas.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema is null", K(ret)); + } else if (!non_partitioned_table_schemas.at(i)->is_index_local_storage() || used_nt_schema_flag.at(i)) { + } else if (OB_FAIL(check_table_conditions_in_common_(partitioned_table_schema, *non_partitioned_table_schemas.at(i), exchange_partition_name, exchange_partition_level, true /*is oracle mode*/))) { + if (in_find_same_aux_table_retry_white_list_(ret)) { + LOG_WARN("all column conditions of exchanging partition tables are not equal, and retry find the matched table", K(ret), K(partitioned_table_schema.get_table_id()), K(non_partitioned_table_schemas.at(i)->get_table_id()), K(exchange_partition_name), K(exchange_partition_level)); + ret = OB_SUCCESS; + } else { + LOG_WARN("all column conditions of exchanging partition tables are not equal, and ret_code not in in_find_same_aux_table_retry_white_list", K(ret), K(partitioned_table_schema.get_table_id()), K(non_partitioned_table_schemas.at(i)->get_table_id()), K(exchange_partition_name), K(exchange_partition_level)); + } + } else if (OB_FAIL(check_table_all_column_conditions_(partitioned_table_schema, *non_partitioned_table_schemas.at(i), true /*is oracle mode*/))) { + // uncertain if other non_partitioned tables match the partitioned table, so try matching other non_partitioned tables + if (in_find_same_aux_table_retry_white_list_(ret)) { + LOG_WARN("all column conditions of exchanging partition tables are not equal, and retry find the matched table", K(ret), K(partitioned_table_schema.get_table_id()), K(non_partitioned_table_schemas.at(i)->get_table_id()), K(exchange_partition_name), K(exchange_partition_level)); + ret = OB_SUCCESS; + } else { + LOG_WARN("all column conditions of exchanging partition tables are not equal, and ret_code not in in_find_same_aux_table_retry_white_list", K(ret), K(partitioned_table_schema.get_table_id()), K(non_partitioned_table_schemas.at(i)->get_table_id()), K(exchange_partition_name), K(exchange_partition_level)); + } + } else { + find_related_nt_schema = true; + used_nt_schema_flag.at(i) = true; + if (OB_FAIL(used_pt_nt_id_map_.set_refactored(partitioned_table_schema.get_table_id(), non_partitioned_table_schemas.at(i)->get_table_id()))) { + LOG_WARN("fail to set refactored pt nt schema mapping", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.at(i)->get_table_id())); + } + } + } + } + return ret; +} + +int ObPartitionExchange::generate_lob_table_mapping_(const ObTableSchema &partitioned_table_schema, + ObIArray &non_partitioned_table_schemas, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + const bool is_oracle_mode, + ObIArray &used_nt_schema_flag, + bool &find_related_nt_schema) +{ + int ret = OB_SUCCESS; + bool is_equal = false; + find_related_nt_schema = false; + if (OB_UNLIKELY(!partitioned_table_schema.is_aux_lob_table() || non_partitioned_table_schemas.count() != used_nt_schema_flag.count() || exchange_partition_name.empty() || PARTITION_LEVEL_ZERO == exchange_partition_level)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(partitioned_table_schema), K(partitioned_table_schema.is_aux_lob_table()), K(non_partitioned_table_schemas.count()), K(used_nt_schema_flag.count()), K(exchange_partition_name), K(exchange_partition_level), K(is_oracle_mode)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && !find_related_nt_schema && i < non_partitioned_table_schemas.count(); i++) { + if (OB_ISNULL(non_partitioned_table_schemas.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema is null", K(ret)); + } else if (!non_partitioned_table_schemas.at(i)->is_aux_lob_table() || used_nt_schema_flag.at(i)) { + } else if ((partitioned_table_schema.is_aux_lob_meta_table() && non_partitioned_table_schemas.at(i)->is_aux_lob_meta_table()) || (partitioned_table_schema.is_aux_lob_piece_table() && non_partitioned_table_schemas.at(i)->is_aux_lob_piece_table())) { + find_related_nt_schema = true; + used_nt_schema_flag.at(i) = true; + if (OB_FAIL(used_pt_nt_id_map_.set_refactored(partitioned_table_schema.get_table_id(), non_partitioned_table_schemas.at(i)->get_table_id()))) { + LOG_WARN("fail to set refactored pt nt schema mapping", K(ret), K(partitioned_table_schema), K(non_partitioned_table_schemas.at(i)->get_table_id())); + } + } + } + } + return ret; +} + +int ObPartitionExchange::update_index_status_(const uint64_t tenant_id, + const uint64_t table_id, + const share::schema::ObIndexStatus status, + const bool in_offline_ddl_white_list, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + const ObTableSchema *index_schema = NULL; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == table_id || status <= INDEX_STATUS_NOT_FOUND || status >= INDEX_STATUS_MAX)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(table_id), K(status), K(in_offline_ddl_white_list)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, table_id, index_schema))) { + LOG_WARN("get table schema failed", K(ret), K(tenant_id), K(table_id), KPC(index_schema)); + } else if (OB_ISNULL(index_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", K(ret), K(tenant_id), K(table_id)); + } else if (OB_UNLIKELY(!index_schema->is_index_table())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("the state that needs to be modified is not the index table", K(ret), K(tenant_id), K(table_id), K(index_schema->is_index_table())); + } else if (OB_FAIL(ddl_operator.update_index_status( + tenant_id, + index_schema->get_data_table_id(), + index_schema->get_table_id(), + status, + in_offline_ddl_white_list, + trans, + nullptr /* ddl_stmt_str */))) { + LOG_WARN("update_index_status failed", K(ret), K(tenant_id), K(index_schema->get_data_table_id()), K(index_schema->get_table_id()), K(status), K(in_offline_ddl_white_list)); + } + return ret; +} + +int ObPartitionExchange::build_single_table_rw_defensive_(const uint64_t tenant_id, + const ObArray &tablet_ids, + const int64_t schema_version, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + ObArray args; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || tablet_ids.empty() || schema_version <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", K(ret), K(tenant_id), K(tablet_ids), K(schema_version)); + } else if (OB_UNLIKELY(!ddl_service_.is_inited())) { + ret = OB_INNER_STAT_ERROR; + LOG_WARN("ddl_service not init", K(ret)); + } else if (OB_FAIL(build_modify_tablet_binding_args_v1_( + tenant_id, tablet_ids, schema_version, args, trans))) { + LOG_WARN("failed to build reuse index args", K(ret)); + } + ObArenaAllocator allocator("DDLRWDefens"); + for (int64_t i = 0; OB_SUCC(ret) && i < args.count(); i++) { + int64_t pos = 0; + int64_t size = args[i].get_serialize_size(); + char *buf = nullptr; + allocator.reuse(); + if (OB_ISNULL(buf = static_cast(allocator.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate", K(ret)); + } else if (OB_FAIL(args[i].serialize(buf, size, pos))) { + LOG_WARN("failed to serialize arg", K(ret)); + } else if (OB_FAIL(trans.register_tx_data(args[i].tenant_id_, args[i].ls_id_, transaction::ObTxDataSourceType::UNBIND_TABLET_NEW_MDS, buf, pos))) { + LOG_WARN("failed to register tx data", K(ret)); + } + } + return ret; +} + +int ObPartitionExchange::build_modify_tablet_binding_args_v1_(const uint64_t tenant_id, + const ObArray &tablet_ids, + const int64_t schema_version, + ObIArray &modify_args, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + ObArray tablets; + if (OB_FAIL(get_tablets_(tenant_id, tablet_ids, tablets, trans))) { + LOG_WARN("failed to get tablet ids of orig table", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < tablets.count(); i++) { + const ObLSID &ls_id = tablets[i].first; + int64_t j = 0; + for (; j < modify_args.count(); j++) { + if (modify_args.at(j).ls_id_ == ls_id && modify_args.at(j).tenant_id_ == tenant_id) { + break; + } + } + if (j == modify_args.count()) { + ObBatchUnbindTabletArg modify_arg; + modify_arg.tenant_id_ = tenant_id; + modify_arg.ls_id_ = ls_id; + modify_arg.schema_version_ = schema_version; + if (OB_FAIL(modify_args.push_back(modify_arg))) { + LOG_WARN("failed to push back modify arg", K(ret)); + } + } + if (OB_SUCC(ret)) { + if (0 <= j && j < modify_args.count()) { + ObBatchUnbindTabletArg &modify_arg = modify_args.at(j); + const ObTabletID &tablet_id = tablets[i].second; + if (OB_FAIL(modify_arg.hidden_tablet_ids_.push_back(tablet_id))) { + LOG_WARN("failed to push back", K(ret)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Array idx out of bounds", K(ret), K(j), K(modify_args.count())); + } + } + } + LOG_DEBUG("build modify tablet binding args", K(ret), K(modify_args)); + return ret; +} + +int ObPartitionExchange::get_tablets_(const uint64_t tenant_id, + const ObArray &tablet_ids, + ObIArray &tablets, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + ObArray ls_ids; + tablets.reset(); + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || tablet_ids.count() < 1)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(tablet_ids)); + } else if (OB_FAIL(ObTabletToLSTableOperator::batch_get_ls(trans, tenant_id, tablet_ids, ls_ids))) { + LOG_WARN("failed to batch get ls", K(ret)); + } else if (OB_UNLIKELY(tablet_ids.count() != ls_ids.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid tablet ids ls ids", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_ids.count(); i++) { + if (OB_FAIL(tablets.push_back({ls_ids[i], tablet_ids[i]}))) { + LOG_WARN("failed to push back tablet id and ls id", K(ret)); + } + } + return ret; +} + +int ObPartitionExchange::adapting_cdc_changes_in_exchange_partition_(const uint64_t tenant_id, + const uint64_t partitioned_table_id, + const uint64_t non_partitioned_table_id, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == partitioned_table_id || OB_INVALID_ID == non_partitioned_table_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(partitioned_table_id), K(non_partitioned_table_id)); + } else if (OB_FAIL(used_pt_nt_id_map_.set_refactored(partitioned_table_id, non_partitioned_table_id))) { + LOG_WARN("fail to set refactored pt nt schema mapping", K(ret), K(partitioned_table_id), K(non_partitioned_table_id)); + } else { + ObChangeTabletToTableArg arg; + share::ObLSID ls_id(share::ObLSID::SYS_LS_ID); + arg.tenant_id_ = tenant_id; + arg.ls_id_ = ls_id; + arg.base_table_id_ = partitioned_table_id; + arg.inc_table_id_ = non_partitioned_table_id; + common::hash::ObHashMap::iterator iter_table; + for (iter_table = used_pt_nt_id_map_.begin(); OB_SUCC(ret) && iter_table != used_pt_nt_id_map_.end(); ++iter_table) { + ObTabletID tmp_tablet; + if (OB_FAIL(arg.table_ids_.push_back(iter_table->first))) { + LOG_WARN("failed to push back table id", K(ret), K(iter_table->first)); + } else if (OB_FAIL(used_table_to_tablet_id_map_.get_refactored(iter_table->second, tmp_tablet))) { + LOG_WARN("get_refactored tablet id from used_table_to_tablet_id_map failed", K(ret), K(iter_table->second), K(tmp_tablet)); + } else if (OB_FAIL(arg.tablet_ids_.push_back(tmp_tablet))) { + LOG_WARN("failed to push back tablet id", K(ret), K(tmp_tablet)); + } else if (OB_FAIL(arg.table_ids_.push_back(iter_table->second))) { + LOG_WARN("failed to push back table id", K(ret), K(iter_table->second)); + } else if (OB_FAIL(used_table_to_tablet_id_map_.get_refactored(iter_table->first, tmp_tablet))) { + LOG_WARN("get_refactored tablet id from used_table_to_tablet_id_map failed", K(ret), K(iter_table->first), K(tmp_tablet)); + } else if (OB_FAIL(arg.tablet_ids_.push_back(tmp_tablet))) { + LOG_WARN("failed to push back tablet id", K(ret), K(tmp_tablet)); + } + } + if (OB_SUCC(ret)) { + if (OB_UNLIKELY(arg.table_ids_.count() != arg.tablet_ids_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exchange partitions num are different tables num", K(ret), K(arg.table_ids_.count()), K(arg.tablet_ids_.count())); + } else { + int64_t pos = 0; + int64_t size = arg.get_serialize_size(); + ObArenaAllocator allocator; + char *buf = nullptr; + if (OB_ISNULL(buf = static_cast(allocator.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate", K(ret)); + } else if (OB_FAIL(arg.serialize(buf, size, pos))) { + LOG_WARN("failed to serialize arg", K(ret)); + } else if (OB_FAIL(trans.register_tx_data(arg.tenant_id_, arg.ls_id_, transaction::ObTxDataSourceType::CHANGE_TABLET_TO_TABLE_MDS, buf, pos))) { + LOG_WARN("failed to register tx data", K(ret)); + } + } + } + } + return ret; +} + +int ObPartitionExchange::update_autoinc_column_information_(const uint64_t tenant_id, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || !partitioned_table_schema.is_valid() || !non_partitioned_table_schema.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(partitioned_table_schema), K(non_partitioned_table_schema)); + } else { + const ObColumnSchemaV2 *pt_col_schema = NULL; + const ObColumnSchemaV2 *nt_col_schema = NULL; + if (0 != partitioned_table_schema.get_autoinc_column_id() && 0 != non_partitioned_table_schema.get_autoinc_column_id()) { + if (OB_ISNULL(pt_col_schema = partitioned_table_schema.get_column_schema(partitioned_table_schema.get_autoinc_column_id()))) { + ret = OB_SCHEMA_ERROR; + LOG_WARN("fail to get column schema", K(ret), K(partitioned_table_schema), K(partitioned_table_schema.get_autoinc_column_id())); + } else if (OB_ISNULL(nt_col_schema = non_partitioned_table_schema.get_column_schema(non_partitioned_table_schema.get_autoinc_column_id()))) { + ret = OB_SCHEMA_ERROR; + LOG_WARN("fail to get column schema", K(ret), K(partitioned_table_schema), K(partitioned_table_schema.get_autoinc_column_id())); + } else { + uint64_t pt_sequence_value = 0; + uint64_t nt_sequence_value = 0; + uint64_t pt_column_id = pt_col_schema->get_column_id(); + uint64_t nt_column_id = nt_col_schema->get_column_id(); + uint64_t new_sequence_value = 0; + ObAutoincrementService &auto_inc_service = ObAutoincrementService::get_instance(); + if (OB_FAIL(ddl_operator.get_target_auto_inc_sequence_value(tenant_id, partitioned_table_schema.get_table_id(), pt_column_id, pt_sequence_value, trans))) { + LOG_WARN("get sequence value failed", K(ret), K(tenant_id), K(partitioned_table_schema.get_table_id()), K(pt_column_id), K(pt_sequence_value)); + } else if (OB_FAIL(ddl_operator.get_target_auto_inc_sequence_value(tenant_id, non_partitioned_table_schema.get_table_id(), nt_column_id, nt_sequence_value, trans))) { + LOG_WARN("get sequence value failed", K(ret), K(tenant_id), K(non_partitioned_table_schema.get_table_id()), K(nt_column_id), K(nt_sequence_value)); + } else if (FALSE_IT(new_sequence_value = max(pt_sequence_value, nt_sequence_value))) { + } else if (OB_FAIL(ddl_operator.set_target_auto_inc_sync_value(tenant_id, partitioned_table_schema.get_table_id(), pt_column_id, new_sequence_value, new_sequence_value - 1, trans))) { + LOG_WARN("set sequence value failed", K(ret), K(tenant_id), K(partitioned_table_schema.get_table_id()), K(pt_column_id), K(new_sequence_value)); + } else if (OB_FAIL(ddl_operator.set_target_auto_inc_sync_value(tenant_id, non_partitioned_table_schema.get_table_id(), nt_column_id, new_sequence_value, new_sequence_value - 1, trans))) { + LOG_WARN("set sequence value failed", K(ret), K(tenant_id), K(non_partitioned_table_schema.get_table_id()), K(nt_column_id), K(new_sequence_value)); + } + } + } + } + return ret; +} + +int ObPartitionExchange::update_identity_column_information_(const uint64_t tenant_id, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || !partitioned_table_schema.is_valid() || !non_partitioned_table_schema.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(partitioned_table_schema), K(non_partitioned_table_schema)); + } else { + ObTableSchema::const_column_iterator pt_iter_begin = partitioned_table_schema.column_begin(); + ObTableSchema::const_column_iterator pt_iter_end = partitioned_table_schema.column_end(); + ObTableSchema::const_column_iterator nt_iter_begin = non_partitioned_table_schema.column_begin(); + ObTableSchema::const_column_iterator nt_iter_end = non_partitioned_table_schema.column_end(); + ObColumnSchemaV2 *pt_col_schema = NULL; + ObColumnSchemaV2 *nt_col_schema = NULL; + ObArenaAllocator allocator(lib::ObLabel("ExchangePart")); + while (OB_SUCC(ret) && OB_SUCC(get_next_pair_column_schema_(pt_iter_begin, pt_iter_end, nt_iter_begin, nt_iter_end, is_oracle_mode, pt_col_schema, nt_col_schema))) { + if (OB_ISNULL(pt_col_schema) || OB_ISNULL(nt_col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to column schema", K(ret), KPC(pt_col_schema), KPC(nt_col_schema)); + } else if (pt_col_schema->is_identity_column() && nt_col_schema->is_identity_column()) { + const ObSequenceSchema *pt_sequence_schema = NULL; + const ObSequenceSchema *nt_sequence_schema = NULL; + ObSequenceSchema pt_tmp_sequence_schema; + ObSequenceSchema nt_tmp_sequence_schema; + common::number::ObNumber pt_next_value; + common::number::ObNumber nt_next_value; + common::number::ObNumber max_next_value; + if (OB_FAIL(schema_guard.get_sequence_schema(pt_col_schema->get_tenant_id(), + pt_col_schema->get_sequence_id(), + pt_sequence_schema))) { + LOG_WARN("get sequence schema fail", K(ret), KPC(pt_col_schema)); + } else if (OB_ISNULL(pt_sequence_schema)) { + ret = OB_SCHEMA_ERROR; + LOG_WARN("fail to get sequence schema", K(ret), K(pt_col_schema->get_tenant_id()), K(pt_col_schema->get_sequence_id()), KPC(pt_col_schema)); + } else if (OB_FAIL(schema_guard.get_sequence_schema(nt_col_schema->get_tenant_id(), + nt_col_schema->get_sequence_id(), + nt_sequence_schema))) { + LOG_WARN("get sequence schema fail", K(ret), KPC(nt_col_schema)); + } else if (OB_ISNULL(nt_sequence_schema)) { + ret = OB_SCHEMA_ERROR; + LOG_WARN("fail to get sequence schema", K(ret), K(nt_col_schema->get_tenant_id()), K(nt_col_schema->get_sequence_id()), KPC(nt_col_schema)); + } else if (OB_FAIL(ddl_operator.get_target_sequence_sync_value(tenant_id, + pt_sequence_schema->get_sequence_id(), + trans, + allocator, + pt_next_value))) { + LOG_WARN("fail to get target sequence sync value", K(ret), KPC(pt_col_schema)); + } else if (OB_FAIL(ddl_operator.get_target_sequence_sync_value(tenant_id, + nt_sequence_schema->get_sequence_id(), + trans, + allocator, + nt_next_value))) { + LOG_WARN("fail to get target sequence sync value", K(ret), KPC(nt_col_schema)); + } else if (OB_FAIL(pt_tmp_sequence_schema.assign(*pt_sequence_schema))) { + LOG_WARN("fail to assign sequence schema", K(ret)); + } else if (OB_FAIL(nt_tmp_sequence_schema.assign(*nt_sequence_schema))) { + LOG_WARN("fail to assign sequence schema", K(ret)); + } else { + if (1 == pt_next_value.compare(nt_next_value)) { + max_next_value = pt_next_value; + } else { + max_next_value = nt_next_value; + } + if (OB_FAIL(pt_tmp_sequence_schema.set_start_with(max_next_value))) { + LOG_WARN("fail to set sequence start with", K(ret), K(max_next_value)); + } else if (OB_FAIL(nt_tmp_sequence_schema.set_start_with(max_next_value))) { + LOG_WARN("fail to set sequence start with", K(ret), K(max_next_value)); + } else if (OB_FAIL(ddl_operator.alter_target_sequence_start_with(pt_tmp_sequence_schema, trans))) { + LOG_WARN("fail to alter target sequence start with", K(ret), K(max_next_value), K(pt_tmp_sequence_schema)); + } else if (OB_FAIL(ddl_operator.alter_target_sequence_start_with(nt_tmp_sequence_schema, trans))) { + LOG_WARN("fail to alter target sequence start with", K(ret), K(max_next_value), K(nt_tmp_sequence_schema)); + } + } + } + } + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + } else { + LOG_WARN("fail to update identity column information", K(ret), K(tenant_id), K(partitioned_table_schema), K(non_partitioned_table_schema), K(is_oracle_mode)); + } + } + return ret; +} + +int ObPartitionExchange::sync_exchange_partition_stats_info_(const uint64_t tenant_id, + const uint64_t new_table_id, + const uint64_t new_stat_level, + const int64_t old_partition_id, + const int64_t new_partition_id, + const ObTabletID &tablet_id, + const ObTableSchema &orig_table_schema, + ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + int64_t affected_rows = 0; + ObSqlString sql_string; + const uint64_t exec_tenant_id = ObSchemaUtils::get_exec_tenant_id(tenant_id); + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == new_table_id || StatLevel::INVALID_LEVEL == new_stat_level || OB_INVALID_ID == old_partition_id || + OB_INVALID_ID == new_partition_id || !tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(new_table_id), K(new_stat_level), K(old_partition_id), K(new_partition_id), K(tablet_id)); + } else if (OB_FAIL(sql_string.assign_fmt("UPDATE %s SET table_id = %ld, partition_id = %ld, object_type = %ld" + " WHERE tenant_id = %ld and table_id = %ld and partition_id = %ld", + OB_ALL_TABLE_STAT_TNAME, new_table_id, new_partition_id, new_stat_level, + ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id), orig_table_schema.get_table_id(), old_partition_id))) { + LOG_WARN("fail to assign sql string", K(ret), K(new_table_id), K(new_partition_id), K(new_stat_level), K(tenant_id), K(orig_table_schema.get_table_id()), K(old_partition_id)); + } else if (OB_FAIL(trans.write(tenant_id, sql_string.ptr(), affected_rows))) { + LOG_WARN("fail to update __all_table_stat", K(ret), K(sql_string)); + } else if (OB_FAIL(update_table_all_monitor_modified_(tenant_id, new_table_id, tablet_id, orig_table_schema, trans))) { + LOG_WARN("fail to update table __all_monitor_modified", K(ret), K(tenant_id), K(new_table_id), K(tablet_id), K(orig_table_schema)); + } else { + ObTableSchema::const_column_iterator iter = orig_table_schema.column_begin(); + ObTableSchema::const_column_iterator iter_end = orig_table_schema.column_end(); + for (; OB_SUCC(ret) && iter != iter_end; iter++) { + const ObColumnSchemaV2 *col = *iter; + ObSqlString column_sql_string; + ObSqlString histogram_sql_string; + if (OB_ISNULL(col)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("col is NULL", K(ret)); + } else if (col->get_column_id() < OB_APP_MIN_COLUMN_ID) { + // bypass hidden column + } else if (col->is_udt_hidden_column()) { + // bypass udt hidden column + } else if (OB_FAIL(column_sql_string.assign_fmt("UPDATE %s SET table_id = %ld, partition_id = %ld, column_id = %ld, object_type = %ld" + " WHERE tenant_id = %ld and table_id = %ld and partition_id = %ld and column_id = %ld", + OB_ALL_COLUMN_STAT_TNAME, new_table_id, new_partition_id, col->get_column_id(), new_stat_level, + ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id), orig_table_schema.get_table_id(), old_partition_id, col->get_column_id()))) { + LOG_WARN("fail to assign sql string", K(ret), K(new_table_id), K(new_partition_id), K(col->get_column_id()), K(new_stat_level), K(tenant_id), K(orig_table_schema.get_table_id()), K(old_partition_id), K(col->get_column_id())); + } else if (OB_FAIL(histogram_sql_string.assign_fmt("UPDATE %s SET table_id = %ld, partition_id = %ld, column_id = %ld, object_type = %ld" + " WHERE tenant_id = %ld and table_id = %ld and partition_id = %ld and column_id = %ld", + OB_ALL_HISTOGRAM_STAT_TNAME, new_table_id, new_partition_id, col->get_column_id(), new_stat_level, + ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id), orig_table_schema.get_table_id(), old_partition_id, col->get_column_id()))) { + LOG_WARN("fail to assign sql string", K(ret), K(new_table_id), K(new_partition_id), K(col->get_column_id()), K(new_stat_level), K(tenant_id), K(orig_table_schema.get_table_id()), K(old_partition_id), K(col->get_column_id())); + } else if (OB_FAIL(trans.write(tenant_id, column_sql_string.ptr(), affected_rows))) { + LOG_WARN("fail to update __all_column_stat", K(ret), K(tenant_id), K(column_sql_string)); + } else if (OB_FAIL(trans.write(tenant_id, histogram_sql_string.ptr(), affected_rows))) { + LOG_WARN("fail to update __all_histogram_stat", K(ret), K(tenant_id), K(histogram_sql_string)); + } + } + } + return ret; +} + +int ObPartitionExchange::update_table_all_monitor_modified_(const uint64_t tenant_id, const uint64_t new_table_id, const ObTabletID &tablet_id, const ObTableSchema &orig_table_schema, ObDDLSQLTransaction &trans) +{ + int ret = OB_SUCCESS; + int64_t affected_rows = 0; + ObSqlString monitor_modified_read_sql_string; + ObSqlString monitor_modified_insert_sql_string; + ObSqlString monitor_modified_delete_sql_string; + const uint64_t exec_tenant_id = ObSchemaUtils::get_exec_tenant_id(tenant_id); + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == new_table_id || !tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(new_table_id), K(tablet_id)); + } else if (OB_FAIL(monitor_modified_read_sql_string.assign_fmt("SELECT last_inserts, last_updates, last_deletes, inserts, updates, deletes FROM %s WHERE tenant_id = %ld and table_id = %ld and tablet_id = %ld", + OB_ALL_MONITOR_MODIFIED_TNAME, ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id), orig_table_schema.get_table_id(), tablet_id.id()))) { + LOG_WARN("fail to assign sql string", K(ret), K(tenant_id), K(orig_table_schema.get_table_id()), K(tablet_id)); + } else { + bool need_update = false; + int64_t last_inserts = 0; + int64_t last_updates = 0; + int64_t last_deletes = 0; + int64_t inserts = 0; + int64_t updates = 0; + int64_t deletes = 0; + common::sqlclient::ObMySQLResult *result = NULL; + ObSQLClientRetryWeak sql_client_retry_weak(GCTX.sql_proxy_); + SMART_VAR(ObMySQLProxy::MySQLResult, res) { + if (OB_FAIL(sql_client_retry_weak.read(res, tenant_id, monitor_modified_read_sql_string.ptr()))) { + LOG_WARN("fail to execute sql", K(ret), K(monitor_modified_read_sql_string)); + } else if (NULL == (result = res.get_result())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail query sql", K(ret)); + } else if (OB_FAIL(result->next())) { + if (common::OB_ITER_END == ret) { + ret = OB_SUCCESS; + } else { + LOG_WARN("fail to get next result", K(ret), K(tenant_id)); + } + } else { + need_update = true; + EXTRACT_INT_FIELD_MYSQL(*result, "last_inserts", last_inserts, int64_t); + EXTRACT_INT_FIELD_MYSQL(*result, "last_updates", last_updates, int64_t); + EXTRACT_INT_FIELD_MYSQL(*result, "last_deletes", last_deletes, int64_t); + EXTRACT_INT_FIELD_MYSQL(*result, "inserts", inserts, int64_t); + EXTRACT_INT_FIELD_MYSQL(*result, "updates", updates, int64_t); + EXTRACT_INT_FIELD_MYSQL(*result, "deletes", deletes, int64_t); + } + } + if (OB_SUCC(ret) && need_update) { + if (OB_FAIL(monitor_modified_insert_sql_string.assign_fmt("INSERT INTO %s(tenant_id, table_id, tablet_id, last_inserts, last_updates, last_deletes, inserts, updates, deletes) VALUES (%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld) ON DUPLICATE KEY UPDATE tenant_id = %ld, table_id = %ld, tablet_id = %ld", OB_ALL_MONITOR_MODIFIED_TNAME, + ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id), new_table_id, tablet_id.id(), last_inserts, last_updates, last_deletes, inserts, updates, deletes, ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id), new_table_id, tablet_id.id()))) { + LOG_WARN("fail to assign sql string", K(ret)); + } else if (OB_FAIL(monitor_modified_delete_sql_string.assign_fmt("DELETE FROM %s WHERE tenant_id = %ld AND table_id = %ld AND tablet_id = %ld", OB_ALL_MONITOR_MODIFIED_TNAME, + ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id), orig_table_schema.get_table_id(), tablet_id.id()))) { + LOG_WARN("fail to assign sql string", K(ret)); + } else if (OB_FAIL(trans.write(tenant_id, monitor_modified_insert_sql_string.ptr(), affected_rows))) { + LOG_WARN("fail to insert __all_monitor_modified", K(ret), K(monitor_modified_insert_sql_string)); + } else if (OB_FAIL(trans.write(tenant_id, monitor_modified_delete_sql_string.ptr(), affected_rows))) { + LOG_WARN("fail to delete __all_monitor_modified", K(ret), K(monitor_modified_delete_sql_string)); + } + } + } + return ret; +} + +int ObPartitionExchange::get_object_id_from_partition_schema_(ObPartitionSchema &partition_schema, const bool get_subpart_only, int64_t &object_id) +{ + int ret = OB_SUCCESS; + object_id = OB_INVALID_PARTITION_ID; + int64_t partition_num = partition_schema.get_partition_num(); + ObPartitionLevel part_level = partition_schema.get_part_level(); + ObPartition** part_array = partition_schema.get_part_array(); + if (OB_UNLIKELY(1 != partition_num)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("partition num is not equal 1", K(ret), K(partition_num)); + } else if (OB_ISNULL(part_array)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("part_array is empty", K(ret)); + } else { + ObPartition* part = part_array[0]; + if (OB_ISNULL(part)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("part is null", K(ret)); + } else if (!get_subpart_only) { + object_id = part->get_part_id(); + } else if (OB_ISNULL(part->get_subpart_array()) || 1 != part->get_subpartition_num()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sub_part_array is null or invalid subpartition num", K(ret)); + } else { + ObSubPartition *subpart = part->get_subpart_array()[0]; + if (OB_ISNULL(subpart)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("subpart is null", K(ret)); + } else { + object_id = subpart->get_sub_part_id(); + } + } + } + return ret; +} + +bool ObChangeTabletToTableArg::is_valid() const { return OB_INVALID_TENANT_ID != tenant_id_ && ls_id_.is_valid() && OB_INVALID_ID != base_table_id_ + && OB_INVALID_ID != inc_table_id_ && tablet_ids_.count() > 0 && table_ids_.count() > 0 && tablet_ids_.count() == table_ids_.count(); } + +int ObChangeTabletToTableArg::assign(const ObChangeTabletToTableArg &other) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(tablet_ids_.assign(other.tablet_ids_))) { + LOG_WARN("fail to assign", K(ret), K(other.tablet_ids_)); + } else if (OB_FAIL(table_ids_.assign(other.table_ids_))) { + LOG_WARN("fail to assign", K(ret), K(other.table_ids_)); + } else { + tenant_id_ = other.tenant_id_; + ls_id_ = other.ls_id_; + base_table_id_ = other.base_table_id_; + inc_table_id_ = other.inc_table_id_; + } + return ret; +} + +OB_SERIALIZE_MEMBER(ObChangeTabletToTableArg, tenant_id_, ls_id_, base_table_id_, inc_table_id_, table_ids_, tablet_ids_); + +}//end namespace rootserver +}//end namespace oceanbase diff --git a/src/rootserver/ob_partition_exchange.h b/src/rootserver/ob_partition_exchange.h new file mode 100644 index 000000000..6e04376d4 --- /dev/null +++ b/src/rootserver/ob_partition_exchange.h @@ -0,0 +1,296 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_ROOTSERVER_OB_PARTITION_EXCHANGE_H_ +#define OCEANBASE_ROOTSERVER_OB_PARTITION_EXCHANGE_H_ + +#include "lib/container/ob_array.h" +#include "share/ob_ddl_task_executor.h" +#include "share/ob_rpc_struct.h" +#include "share/schema/ob_schema_struct.h" +#include "storage/tablet/ob_tablet_binding_helper.h" + +namespace oceanbase +{ +namespace share +{ +class AutoincParam; +namespace schema +{ +class ObTableSchema; +} +} +namespace rootserver +{ +class ObDDLService; +class ObDDLSQLTransaction; +class ObPartitionExchange final +{ +public: + typedef std::pair LSTabletID; + explicit ObPartitionExchange(ObDDLService &ddl_service); + ~ObPartitionExchange(); + int check_and_exchange_partition(const obrpc::ObExchangePartitionArg &arg, obrpc::ObAlterTableRes &res, ObSchemaGetterGuard &schema_guard); +private: + int check_partition_exchange_conditions_(const obrpc::ObExchangePartitionArg &arg, const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode, ObSchemaGetterGuard &schema_guard); + int do_exchange_partition_(const obrpc::ObExchangePartitionArg &arg, obrpc::ObAlterTableRes &res, const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode, ObSchemaGetterGuard &schema_guard); + int lock_exchange_data_table_and_partition_(const uint64_t tenant_id, const ObTableSchema &partitioned_table_schema, const ObTableSchema &non_partitioned_table_schema, const common::ObTabletID &tablet_id, ObDDLSQLTransaction &trans); + int check_data_table_partition_exchange_conditions_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const ObString &exchange_partition_name, const ObPartitionLevel exchange_partition_level,const bool is_oracle_mode); + // table level conditions that need to be checked for partition exchange in mysql mode and oracle mode + int check_table_conditions_in_common_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const ObString &exchange_partition_name, const ObPartitionLevel exchange_partition_level, const bool is_oracle_mode); + // table level conditions that need to be checked for partition exchange in mysql mode + int check_table_conditions_in_mysql_mode_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema); + // table level conditions that need to be checked for partition exchange in oracle mode + int check_table_conditions_in_oracle_mode_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema); + int check_partition_and_table_tablespace_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const ObString &exchange_partition_name, const ObPartitionLevel exchange_partition_level, const bool is_oracle_mode); + int check_table_index_infos_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode); + int check_table_lob_infos_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode); + int check_table_rowkey_infos_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode); + int compare_two_rowkey_info_(const common::ObRowkeyInfo &l_rowkey_info, const common::ObRowkeyInfo &r_rowkey_info, bool &is_equal); + int check_table_column_groups_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode); + int compare_two_column_group_schema_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const ObColumnGroupSchema &base_cg_schema, const ObColumnGroupSchema &inc_cg_schema, const bool is_oracle_mode, bool &is_equal); + // verify if the check constraints of two tables meet the requirements + int check_table_constraints_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode); + int check_table_all_column_conditions_(const ObTableSchema &base_table_schema, const ObTableSchema &inc_table_schema, const bool is_oracle_mode); + int check_column_level_conditions_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_aux_table_column, const bool is_oracle_mode); + int check_column_conditions_in_common_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_oracle_mode); + int check_column_conditions_in_mysql_mode_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_aux_table_column); + int check_column_conditions_in_oracle_mode_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_aux_table_column); + int check_generate_column_conditions_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, bool &is_equal); + int check_column_flags_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, bool &is_equal); + int check_column_default_value_(const ObColumnSchemaV2 *base_table_col_schema, const ObColumnSchemaV2 *inc_table_col_schema, const bool is_oracle_mode, bool &is_equal); + int compare_default_value_(ObObj &l_value, ObObj &r_value, const bool is_oracle_mode, bool &is_equal); + int get_next_pair_column_schema_(ObTableSchema::const_column_iterator &base_iter_begin, + ObTableSchema::const_column_iterator &base_iter_end, + ObTableSchema::const_column_iterator &inc_iter_begin, + ObTableSchema::const_column_iterator &inc_iter_end, + const bool is_oracle_mode, + ObColumnSchemaV2 *&base_table_col_schema, + ObColumnSchemaV2 *&inc_table_col_schema); + int get_next_need_check_column_(ObTableSchema::const_column_iterator &iter_begin, ObTableSchema::const_column_iterator &iter_end, const bool is_oracle_mode, ObColumnSchemaV2 *&table_col_schema); + int set_global_storage_index_unusable_(const uint64_t tenant_id, + const ObTableSchema &partitioned_data_table_schema, + const ObTableSchema &non_partitioned_data_table_schema, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int get_data_partition_and_index_(const ObTableSchema &partitioned_data_table_schema, const ObString &data_part_name, const ObPartition *&data_part, int64_t &data_partition_index); + int get_data_subpartition_and_index_(const ObTableSchema &partitioned_data_table_schema, + const ObString &data_subpart_name, + const ObPartition *&data_part, + const ObSubPartition *&data_subpart, + int64_t &data_partition_index, + int64_t &data_subpartition_index); + int exchange_data_table_partition_(const uint64_t tenant_id, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const ObPartition &part, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int exchange_data_table_subpartition_(const uint64_t tenant_id, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const ObPartition &part, + const ObSubPartition &subpart, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int exchange_auxiliary_table_partition_(const uint64_t tenant_id, + const int64_t ori_data_partition_index, + const ObPartition &ori_data_part, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int exchange_auxiliary_table_subpartition_(const uint64_t tenant_id, + const int64_t ori_data_partition_index, + const int64_t ori_data_subpartition_index, + const ObPartition &ori_data_part, + const ObSubPartition &ori_data_subpart, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int exchange_partition_map_relationship_(const uint64_t tenant_id, + const ObPartition &part, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int exchange_subpartition_map_relationship_(const uint64_t tenant_id, + const ObPartition &part, + const ObSubPartition &subpart, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int update_exchange_table_non_schema_attributes_(const uint64_t tenant_id, + const int64_t old_partition_id, + const int64_t new_partition_id, + const bool is_exchange_subpartition, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const ObIArray &exchange_table_ids, + const ObIArray &exchange_tablet_ids, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int update_exchange_table_level_attributes_(const uint64_t tenant_id, + const ObIArray &exchange_table_ids, + const ObIArray &exchange_tablet_ids, + ObTableSchema &partitioned_table_schema, + ObTableSchema &non_partitioned_table_schema, + ObDDLSQLTransaction &trans); + int update_table_to_tablet_id_mapping_(const uint64_t tenant_id, + const ObIArray &table_ids, + const ObIArray &tablet_ids, + ObDDLSQLTransaction &trans); + int refresh_table_schema_version_(const uint64_t tenant_id, ObTableSchema &table_schema); + int update_table_attribute_(const ObTableSchema &table_schema, + ObDDLSQLTransaction &trans); + int push_data_table_schema_version_(const uint64_t tenant_id, + const ObTableSchema &table_schema, + const common::ObString *ddl_stmt_str, + const uint64_t exchange_data_table_id, + int64_t &new_schema_version, + ObDDLSQLTransaction &trans); + int get_local_storage_index_and_lob_table_schemas_(const ObTableSchema &table_schema, + const bool is_pt_schema, + const bool is_oracle_mode, + ObIArray &table_schemas, + ObSchemaGetterGuard &schema_guard); + int check_auxiliary_schema_conditions_(const ObTableSchema *table_schema, const bool is_oracle_mode); + int compare_column_extended_type_info_(const common::ObIArray &l_extended_type_info, + const common::ObIArray &r_extended_type_info, + bool &is_equal); + bool in_supported_table_type_white_list_(const ObTableSchema &table_schema); + // generate corresponding auxiliary table mapping that need to exchange partitions + bool in_find_same_aux_table_retry_white_list_(const int ret_code); + int generate_auxiliary_table_mapping_(const ObTableSchema &partitioned_data_table_schema, + const ObTableSchema &non_partitioned_data_table_schema, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + const bool is_oracle_mode, + ObSchemaGetterGuard &schema_guard); + int generate_local_storage_index_and_lob_table_mapping_(const ObTableSchema &partitioned_table_schema, + ObIArray &non_partitioned_table_schemas, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + const bool is_oracle_mode, + ObIArray &used_nt_schema_flag); + int generate_local_storage_index_table_mapping_in_mysql_mode_(const ObTableSchema &partitioned_table_schema, + ObIArray &non_partitioned_table_schemas, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + ObIArray &used_nt_schema_flag, + bool &find_related_nt_schema); + int generate_local_storage_index_table_mapping_in_oracle_mode_(const ObTableSchema &partitioned_table_schema, + ObIArray &non_partitioned_table_schemas, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + ObIArray &used_nt_schema_flag, + bool &find_related_nt_schema); + int generate_lob_table_mapping_(const ObTableSchema &partitioned_table_schema, + ObIArray &non_partitioned_table_schemas, + const ObString &exchange_partition_name, + const ObPartitionLevel exchange_partition_level, + const bool is_oracle_mode, + ObIArray &used_nt_schema_flag, + bool &find_related_nt_schema); + int update_index_status_(const uint64_t tenant_id, + const uint64_t table_id, + const share::schema::ObIndexStatus status, + const bool in_offline_ddl_white_list, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + // Register MDS for read and write defense verification after single table ddl + int build_single_table_rw_defensive_(const uint64_t tenant_id, + const ObArray &tablet_ids, + const int64_t schema_version, + ObDDLSQLTransaction &trans); + int build_modify_tablet_binding_args_v1_(const uint64_t tenant_id, + const ObArray &tablet_ids, + const int64_t schema_version, + ObIArray &modify_args, + ObDDLSQLTransaction &trans); + int get_tablets_(const uint64_t tenant_id, + const ObArray &tablet_ids, + ObIArray &tablets, + ObDDLSQLTransaction &trans); + int adapting_cdc_changes_in_exchange_partition_(const uint64_t tenant_id, + const uint64_t partitioned_table_id, + const uint64_t non_partitioned_table_id, + ObDDLSQLTransaction &trans); + int update_autoinc_column_information_(const uint64_t tenant_id, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans); + int update_identity_column_information_(const uint64_t tenant_id, + const ObTableSchema &partitioned_table_schema, + const ObTableSchema &non_partitioned_table_schema, + const bool is_oracle_mode, + ObDDLOperator &ddl_operator, + ObDDLSQLTransaction &trans, + ObSchemaGetterGuard &schema_guard); + int sync_exchange_partition_stats_info_(const uint64_t tenant_id, + const uint64_t new_table_id, + const uint64_t new_stat_level, + const int64_t old_partition_id, + const int64_t new_partition_id, + const ObTabletID &tablet_id, + const ObTableSchema &orig_table_schema, + ObDDLSQLTransaction &trans); + int update_table_all_monitor_modified_(const uint64_t tenant_id, const uint64_t new_table_id, const ObTabletID &tablet_id, const ObTableSchema &orig_table_schema, ObDDLSQLTransaction &trans); + int get_object_id_from_partition_schema_(ObPartitionSchema &partition_schema, const bool get_subpart_only, int64_t &object_id); +private: + ObDDLService &ddl_service_; + common::hash::ObHashMap used_pt_nt_id_map_; + common::hash::ObHashMap used_table_to_tablet_id_map_; + common::ObSArray unused_pt_index_id_; + common::ObSArray unused_nt_index_id_; +private: + DISALLOW_COPY_AND_ASSIGN(ObPartitionExchange); +}; + +struct ObChangeTabletToTableArg final +{ + OB_UNIS_VERSION_V(1); +public: + ObChangeTabletToTableArg() : tenant_id_(OB_INVALID_TENANT_ID), ls_id_(), base_table_id_(OB_INVALID_ID), inc_table_id_(OB_INVALID_ID), tablet_ids_(), table_ids_() {} + ~ObChangeTabletToTableArg() {} + bool is_valid() const; + int assign(const ObChangeTabletToTableArg &other); + uint64_t tenant_id_; + share::ObLSID ls_id_; + uint64_t base_table_id_; // PT table, always with the large amount of data. + uint64_t inc_table_id_; // NT table, with the incremental data. + // tablet ids of data table, index table, lob meta/piece table. + common::ObSArray tablet_ids_; + // the table ids corresponding to the tablet ids. + common::ObSArray table_ids_; + TO_STRING_KV(K_(tenant_id), K_(ls_id), K_(base_table_id), K_(inc_table_id), K_(tablet_ids), K_(table_ids)); +}; + +}//end namespace rootserver +}//end namespace oceanbase + +#endif //OCEANBASE_ROOTSERVER_OB_PARTITION_EXCHANGE_H_ diff --git a/src/rootserver/ob_root_service.cpp b/src/rootserver/ob_root_service.cpp index df65fc056..8ba1f4fb3 100755 --- a/src/rootserver/ob_root_service.cpp +++ b/src/rootserver/ob_root_service.cpp @@ -74,6 +74,7 @@ #include "observer/dbms_scheduler/ob_dbms_sched_job_master.h" #include "rootserver/ob_bootstrap.h" +#include "rootserver/ob_partition_exchange.h" #include "rootserver/ob_schema2ddl_sql.h" #include "rootserver/ob_index_builder.h" #include "rootserver/ob_mlog_builder.h" @@ -4530,6 +4531,45 @@ int ObRootService::alter_table(const obrpc::ObAlterTableArg &arg, obrpc::ObAlter return ret; } +int ObRootService::exchange_partition(const obrpc::ObExchangePartitionArg &arg, obrpc::ObAlterTableRes &res) +{ + int ret = OB_SUCCESS; + uint64_t compat_version = 0; + ObSchemaGetterGuard schema_guard; + ObPartitionExchange partition_exchange(ddl_service_); + schema_guard.set_session_id(arg.session_id_); + LOG_DEBUG("receive exchange partition arg", K(ret), K(arg)); + if (!inited_) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if (!arg.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_FAIL(GET_MIN_DATA_VERSION(arg.tenant_id_, compat_version))) { + LOG_WARN("fail to get data version", K(ret), K(arg.tenant_id_)); + } else if (compat_version < DATA_VERSION_4_3_1_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("data version less than 4.3.1.0 does not support this operation", K(ret), K(compat_version)); + } else if (OB_FAIL(ddl_service_.get_tenant_schema_guard_with_version_in_inner_table(arg.tenant_id_, schema_guard))) { + LOG_WARN("get schema guard in inner table failed", K(ret)); + } else if (OB_FAIL(check_parallel_ddl_conflict(schema_guard, arg))) { + LOG_WARN("check parallel ddl conflict failed", K(ret)); + } else if (OB_FAIL(partition_exchange.check_and_exchange_partition(arg, res, schema_guard))) { + LOG_WARN("fail to check and exchange partition", K(ret), K(arg), K(res)); + } + char table_id_buffer[256]; + snprintf(table_id_buffer, sizeof(table_id_buffer), "table_id:%ld, exchange_table_id:%ld", + arg.base_table_id_, arg.inc_table_id_); + ROOTSERVICE_EVENT_ADD("ddl scheduler", "alter table", + K(arg.tenant_id_), + "ret", ret, + "trace_id", *ObCurTraceId::get_trace_id(), + "table_id", table_id_buffer, + "schema_version", res.schema_version_); + LOG_INFO("finish alter table ddl", K(ret), K(arg), K(res), "ddl_event_info", ObDDLEventInfo()); + return ret; +} + int ObRootService::create_index(const ObCreateIndexArg &arg, obrpc::ObAlterTableRes &res) { int ret = OB_SUCCESS; diff --git a/src/rootserver/ob_root_service.h b/src/rootserver/ob_root_service.h index a08e583cf..cc84cc991 100644 --- a/src/rootserver/ob_root_service.h +++ b/src/rootserver/ob_root_service.h @@ -501,6 +501,7 @@ public: int rename_table(const obrpc::ObRenameTableArg &arg); int truncate_table(const obrpc::ObTruncateTableArg &arg, obrpc::ObDDLRes &res); int truncate_table_v2(const obrpc::ObTruncateTableArg &arg, obrpc::ObDDLRes &res); + int exchange_partition(const obrpc::ObExchangePartitionArg &arg, obrpc::ObAlterTableRes &res); int create_index(const obrpc::ObCreateIndexArg &arg, obrpc::ObAlterTableRes &res); int drop_table(const obrpc::ObDropTableArg &arg, obrpc::ObDDLRes &res); int drop_database(const obrpc::ObDropDatabaseArg &arg, obrpc::ObDropDatabaseRes &drop_database_res); diff --git a/src/rootserver/ob_rs_rpc_processor.h b/src/rootserver/ob_rs_rpc_processor.h index 298408edc..e383ddcd4 100644 --- a/src/rootserver/ob_rs_rpc_processor.h +++ b/src/rootserver/ob_rs_rpc_processor.h @@ -343,6 +343,7 @@ DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_CREATE_TABLE, ObRpcCreateTableP, create_ta DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_RECOVER_RESTORE_TABLE_DDL, ObRpcRecoverRestoreTableDDLP, recover_restore_table_ddl(arg_)); DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_PARALLEL_CREATE_TABLE, ObRpcParallelCreateTableP, parallel_create_table(arg_, result_)); DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_ALTER_TABLE, ObRpcAlterTableP, alter_table(arg_, result_)); +DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_EXCHANGE_PARTITION, ObRpcExchangePartitionP, exchange_partition(arg_, result_)); DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_DROP_TABLE, ObRpcDropTableP, drop_table(arg_, result_)); DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_RENAME_TABLE, ObRpcRenameTableP, rename_table(arg_)); DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_TRUNCATE_TABLE, ObRpcTruncateTableP, truncate_table(arg_, result_)); diff --git a/src/share/ob_common_rpc_proxy.h b/src/share/ob_common_rpc_proxy.h index e1ea8a2be..bbac8be1c 100644 --- a/src/share/ob_common_rpc_proxy.h +++ b/src/share/ob_common_rpc_proxy.h @@ -95,6 +95,7 @@ public: RPC_S(PRD execute_ddl_task, obrpc::OB_EXECUTE_DDL_TASK, (ObAlterTableArg), common::ObSArray); RPC_S(PRD maintain_obj_dependency_info, obrpc::OB_MAINTAIN_OBJ_DEPENDENCY_INFO, (ObDependencyObjDDLArg)); RPC_S(PRD mview_complete_refresh, obrpc::OB_MVIEW_COMPLETE_REFRESH, (obrpc::ObMViewCompleteRefreshArg), obrpc::ObMViewCompleteRefreshRes); + RPC_S(PRD exchange_partition, obrpc::OB_EXCHANGE_PARTITION, (ObExchangePartitionArg), ObAlterTableRes); //----Definitions for managing privileges---- RPC_S(PRD create_user, obrpc::OB_CREATE_USER, (ObCreateUserArg), common::ObSArray); diff --git a/src/share/ob_errno.def b/src/share/ob_errno.def index 4fe984ce8..3e0586c1f 100755 --- a/src/share/ob_errno.def +++ b/src/share/ob_errno.def @@ -2652,7 +2652,6 @@ DEFINE_ERROR_EXT(OB_ERR_ILLEGAL_USER_VAR, -11013, ER_ILLEGAL_USER_VAR, "42000", DEFINE_ERROR(OB_ERR_FT_COLUMN_NOT_INDEXED, -11014, ER_FT_MATCHING_KEY_NOT_FOUND, "HY000", "Can't find FULLTEXT index matching the column list"); DEFINE_ERROR_EXT(OB_ERR_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT, -11015, ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT, "HY000", "Can't update table while ctas is being created.", "Can't update table '%s' while '%s' is being created."); DEFINE_ERROR_EXT(OB_ERR_PARTITION_EXCHANGE_PART_TABLE, -11017, ER_PARTITION_EXCHANGE_PART_TABLE, "HY000", "Table to exchange with partition is partitioned", "Table to exchange with partition is partitioned: \'%.*s\'"); - // 余留位置 //////////////////////////////////////////////////////////////// // SQL扩展区段1:[-11000, -12000) diff --git a/src/share/ob_rpc_struct.cpp b/src/share/ob_rpc_struct.cpp index 64847a3da..11d6e0a75 100755 --- a/src/share/ob_rpc_struct.cpp +++ b/src/share/ob_rpc_struct.cpp @@ -2650,6 +2650,101 @@ OB_DEF_SERIALIZE_SIZE(ObAlterTableArg) return len; } +bool ObExchangePartitionArg::is_valid() const +{ + return OB_INVALID_ID != session_id_ && OB_INVALID_ID != tenant_id_ && PARTITION_LEVEL_ZERO != exchange_partition_level_ && PARTITION_LEVEL_MAX != exchange_partition_level_ && OB_INVALID_ID != base_table_id_ + && !base_table_part_name_.empty() && OB_INVALID_ID != inc_table_id_; +} + +int ObExchangePartitionArg::assign(const ObExchangePartitionArg &other) +{ + int ret = OB_SUCCESS; + if (this == &other) { + //do nothing + } else if (OB_FAIL(ObDDLArg::assign(other))) { + LOG_WARN("assign failed", K(ret)); + } else { + session_id_ = other.session_id_; + tenant_id_ = other.tenant_id_; + exchange_partition_level_ = other.exchange_partition_level_; + base_table_id_ = other.base_table_id_; + base_table_part_name_ = other.base_table_part_name_; + inc_table_id_ = other.inc_table_id_; + including_indexes_ = other.including_indexes_; + without_validation_ = other.without_validation_; + update_global_indexes_ = other.update_global_indexes_; + } + return ret; +} + +OB_DEF_SERIALIZE(ObExchangePartitionArg) +{ + int ret = OB_SUCCESS; + BASE_SER((, ObDDLArg)); + LST_DO_CODE(OB_UNIS_ENCODE, + session_id_, + tenant_id_, + exchange_partition_level_, + base_table_id_, + base_table_part_name_, + inc_table_id_, + including_indexes_, + without_validation_, + update_global_indexes_); + return ret; +} + +OB_DEF_DESERIALIZE(ObExchangePartitionArg) +{ + int ret = OB_SUCCESS; + BASE_DESER((, ObDDLArg)); + LST_DO_CODE(OB_UNIS_DECODE, + session_id_, + tenant_id_, + exchange_partition_level_, + base_table_id_, + base_table_part_name_, + inc_table_id_, + including_indexes_, + without_validation_, + update_global_indexes_); + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObExchangePartitionArg) +{ + int64_t len = ObDDLArg::get_serialize_size(); + LST_DO_CODE(OB_UNIS_ADD_LEN, + session_id_, + tenant_id_, + exchange_partition_level_, + base_table_id_, + base_table_part_name_, + inc_table_id_, + including_indexes_, + without_validation_, + update_global_indexes_); + return len; +} + +DEF_TO_STRING(ObExchangePartitionArg) +{ + int64_t pos = 0; + pos += ObDDLArg::to_string(buf + pos, buf_len - pos); + J_OBJ_START(); + J_KV(K_(session_id), + K_(tenant_id), + K_(exchange_partition_level), + K_(base_table_id), + K_(base_table_part_name), + K_(inc_table_id), + K_(including_indexes), + K_(without_validation), + K_(update_global_indexes)); + J_OBJ_END(); + return pos; +} + bool ObTruncateTableArg::is_valid() const { return OB_INVALID_ID != tenant_id_ && !database_name_.empty() diff --git a/src/share/ob_rpc_struct.h b/src/share/ob_rpc_struct.h index 4907ea379..be8670c45 100755 --- a/src/share/ob_rpc_struct.h +++ b/src/share/ob_rpc_struct.h @@ -2263,6 +2263,41 @@ public: int64_t get_index_args_serialize_size() const; }; +struct ObExchangePartitionArg : public ObDDLArg +{ + OB_UNIS_VERSION(1); +public: + ObExchangePartitionArg(): + ObDDLArg(), + session_id_(common::OB_INVALID_ID), + tenant_id_(common::OB_INVALID_ID), + exchange_partition_level_(PARTITION_LEVEL_MAX), + base_table_id_(common::OB_INVALID_ID), + base_table_part_name_(), + inc_table_id_(common::OB_INVALID_ID), + including_indexes_(true), + without_validation_(true), + update_global_indexes_(false) + { + } + virtual ~ObExchangePartitionArg() + { + } + bool is_valid() const; + int assign(const ObExchangePartitionArg& other); +public: + DECLARE_TO_STRING; + uint64_t session_id_; + uint64_t tenant_id_; + ObPartitionLevel exchange_partition_level_; + uint64_t base_table_id_; // PT table, always contains large amount pf data. + ObString base_table_part_name_; + uint64_t inc_table_id_; // NT table, always contains incremental data. + bool including_indexes_; // default true. + bool without_validation_; // default true. + bool update_global_indexes_; // default false. +}; + struct ObTableItem { OB_UNIS_VERSION(1); diff --git a/src/share/schema/ob_column_schema.h b/src/share/schema/ob_column_schema.h index 9fdbf81dc..262c2191e 100644 --- a/src/share/schema/ob_column_schema.h +++ b/src/share/schema/ob_column_schema.h @@ -300,6 +300,7 @@ int assign(const ObColumnSchemaV2 &src_schema); inline bool is_enum_or_set() const { return meta_type_.is_enum_or_set(); } inline static bool is_hidden_pk_column_id(const uint64_t column_id); + inline bool is_unused() const { return column_flags_ & UNUSED_COLUMN_FLAG; } //other methods int64_t get_convert_size(void) const; diff --git a/src/share/schema/ob_constraint.cpp b/src/share/schema/ob_constraint.cpp index 60fc18353..a62e80ce2 100644 --- a/src/share/schema/ob_constraint.cpp +++ b/src/share/schema/ob_constraint.cpp @@ -96,6 +96,20 @@ int64_t ObConstraint::get_convert_size() const convert_size += column_cnt_ * sizeof(uint64_t); return convert_size; } +/*The following function is used to determine whether the check constraints of the two partition exchange tables are the same. + To ensure that the check constraints are exactly the same, the following conditions need to be met: + 1、rely_flag_、enable_flag_、validate_flag_, these three values are the conditions for determining the constraint state. + 2、constraint_type_, This value determines the type of constraint. + 3、check_expr_, at present, it is required that the expression of the constraint must be exactly the same of the two partition exchange tables. +*/ +bool ObConstraint::is_match_partition_exchange_constraint_conditions(const ObConstraint &r) const +{ + return rely_flag_ == r.get_rely_flag() && + enable_flag_ == r.get_enable_flag() && + validate_flag_ == r.get_validate_flag() && + constraint_type_ == r.get_constraint_type() && + (0 == check_expr_.compare(r.get_check_expr_str())); +} int ObConstraint::get_not_null_column_name(ObString &cst_col_name) const { diff --git a/src/share/schema/ob_constraint.h b/src/share/schema/ob_constraint.h index f99fff34f..08ef2251b 100644 --- a/src/share/schema/ob_constraint.h +++ b/src/share/schema/ob_constraint.h @@ -119,6 +119,7 @@ public: // other int64_t get_convert_size() const; + bool is_match_partition_exchange_constraint_conditions(const ObConstraint &r) const; void reset(); DECLARE_VIRTUAL_TO_STRING; private: diff --git a/src/share/schema/ob_schema_struct.cpp b/src/share/schema/ob_schema_struct.cpp index 782ce2c3f..5a22b1cc6 100644 --- a/src/share/schema/ob_schema_struct.cpp +++ b/src/share/schema/ob_schema_struct.cpp @@ -14448,6 +14448,20 @@ int ObColumnGroupSchema::get_column_group_type_name(ObString &readable_cg_name) } return ret; } +/* +The following function is used by partition exchange to compare whether cg-level attributes are the same and three attributes are not considered. +1、column_group_name: The same column group in the two tables may have different names specified by the user, so no comparison is required. +2、column_group_id: Adding and deleting column groups multiple times to the same table will cause the column group id to increase, and the rules are similar to column ids. Therefore, in two tables, the same column group may have different column group ids. +3、column id contained in column group: Since in the comparison of columns in two tables, the column id of the same column is not necessarily the same, therefore, the column id in the two column groups cannot distinguish whether they are the same column. You need to use the column id to get the column schema and then compare the column attributes in sequence. +*/ +bool ObColumnGroupSchema::has_same_column_group_attributes_for_part_exchange(const ObColumnGroupSchema &other) const +{ + return column_group_type_ == other.get_column_group_type() && + block_size_ == other.get_block_size() && + compressor_type_ == other.get_compressor_type() && + row_store_type_ == other.get_row_store_type() && + column_id_cnt_ == other.get_column_id_count(); +} OB_DEF_SERIALIZE(ObSkipIndexColumnAttr) { diff --git a/src/share/schema/ob_schema_struct.h b/src/share/schema/ob_schema_struct.h index 4b8037174..7ad014fe1 100755 --- a/src/share/schema/ob_schema_struct.h +++ b/src/share/schema/ob_schema_struct.h @@ -8938,6 +8938,7 @@ public: int get_column_id(const int64_t idx, uint64_t &column_id) const; int remove_column_id(const uint64_t column_id); int get_column_group_type_name(ObString &readable_cg_name) const; + bool has_same_column_group_attributes_for_part_exchange(const ObColumnGroupSchema &other) const; VIRTUAL_TO_STRING_KV(K_(column_group_id), K_(column_group_name), diff --git a/src/share/schema/ob_sequence_sql_service.cpp b/src/share/schema/ob_sequence_sql_service.cpp index 2c9b25eda..56e93aa87 100644 --- a/src/share/schema/ob_sequence_sql_service.cpp +++ b/src/share/schema/ob_sequence_sql_service.cpp @@ -92,6 +92,7 @@ int ObSequenceSqlService::alter_sequence_start_with(const ObSequenceSchema &sequ // to get sync value from inner table. int ObSequenceSqlService::get_sequence_sync_value(const uint64_t tenant_id, const uint64_t sequence_id, + const bool is_for_update, common::ObISQLClient &sql_client, ObIAllocator &allocator, common::number::ObNumber &next_value) @@ -100,6 +101,7 @@ int ObSequenceSqlService::get_sequence_sync_value(const uint64_t tenant_id, ObSqlString sql; common::number::ObNumber tmp; const char *tname = OB_ALL_SEQUENCE_VALUE_TNAME; + const char *is_for_update_str = "FOR UPDATE"; SMART_VAR(ObMySQLProxy::MySQLResult, res) { common::sqlclient::ObMySQLResult *result = nullptr; if (OB_FAIL(sql.assign_fmt( @@ -107,29 +109,36 @@ int ObSequenceSqlService::get_sequence_sync_value(const uint64_t tenant_id, "WHERE SEQUENCE_ID = %lu", tname, sequence_id))) { LOG_WARN("fail to format sql", K(ret)); - } else if (OB_FAIL(sql_client.read(res, tenant_id, sql.ptr()))) { - LOG_WARN("fail to execute sql", K(sql), K(ret)); - } else if (nullptr == (result = res.get_result())) { - ret = OB_ENTRY_NOT_EXIST; - LOG_WARN("can't find sequence", K(ret), K(tname), K(tenant_id), K(sequence_id)); - } else if (OB_FAIL(result->next())) { - if (OB_ITER_END != ret) { - LOG_WARN("fail to get next row", K(ret), K(tname), K(tenant_id), K(sequence_id)); - } else { - // OB_ITER_END means there is no record in table, - // thus the sync value is its' start value, and init the table when operate it. + } else if (is_for_update) { + if (OB_FAIL(sql.append_fmt(" %s", is_for_update_str))) { + LOG_WARN("fail to assign sql", K(ret)); } - } else { - EXTRACT_NUMBER_FIELD_MYSQL(*result, NEXT_VALUE, tmp); - if (OB_FAIL(ret)) { - LOG_WARN("fail to get NEXT_VALUE", K(ret)); - } else if (OB_FAIL(next_value.from(tmp, allocator))) { - LOG_WARN("fail to deep copy next_val", K(tmp), K(ret)); - } else if (OB_ITER_END != (ret = result->next())) { - LOG_WARN("expected OB_ITER_END", K(ret)); - ret = (OB_SUCCESS == ret ? OB_ERR_UNEXPECTED : ret); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(sql_client.read(res, tenant_id, sql.ptr()))) { + LOG_WARN("fail to execute sql", K(sql), K(ret)); + } else if (nullptr == (result = res.get_result())) { + ret = OB_ENTRY_NOT_EXIST; + LOG_WARN("can't find sequence", K(ret), K(tname), K(tenant_id), K(sequence_id)); + } else if (OB_FAIL(result->next())) { + if (OB_ITER_END != ret) { + LOG_WARN("fail to get next row", K(ret), K(tname), K(tenant_id), K(sequence_id)); + } else { + // OB_ITER_END means there is no record in table, + // thus the sync value is its' start value, and init the table when operate it. + } } else { - ret = OB_SUCCESS; + EXTRACT_NUMBER_FIELD_MYSQL(*result, NEXT_VALUE, tmp); + if (OB_FAIL(ret)) { + LOG_WARN("fail to get NEXT_VALUE", K(ret)); + } else if (OB_FAIL(next_value.from(tmp, allocator))) { + LOG_WARN("fail to deep copy next_val", K(tmp), K(ret)); + } else if (OB_ITER_END != (ret = result->next())) { + LOG_WARN("expected OB_ITER_END", K(ret)); + ret = (OB_SUCCESS == ret ? OB_ERR_UNEXPECTED : ret); + } else { + ret = OB_SUCCESS; + } } } } @@ -475,6 +484,7 @@ int ObSequenceSqlService::add_sequence_to_value_table(const uint64_t tenant_id, common::number::ObNumber next_value; if (OB_FAIL(get_sequence_sync_value(tenant_id, old_sequence_id, + false,/*is select for update*/ sql_client, allocator, next_value))) { diff --git a/src/share/schema/ob_sequence_sql_service.h b/src/share/schema/ob_sequence_sql_service.h index b08e86f9e..9a6f89011 100644 --- a/src/share/schema/ob_sequence_sql_service.h +++ b/src/share/schema/ob_sequence_sql_service.h @@ -56,6 +56,15 @@ public: const int64_t new_schema_version, common::ObISQLClient *sql_client, const common::ObString *ddl_stmt_str = NULL); + int alter_sequence_start_with(const ObSequenceSchema &sequence_schema, + common::ObISQLClient &sql_client); + int get_sequence_sync_value(const uint64_t tenant_id, + const uint64_t sequence_id, + const bool is_for_update, + common::ObISQLClient &sql_client, + ObIAllocator &allocator, + common::number::ObNumber &next_value); + int clean_sequence_cache(uint64_t tenant_id, uint64_t sequence_id); private: int add_sequence(common::ObISQLClient &sql_client, const ObSequenceSchema &sequence_schema, const bool only_history, const uint64_t *old_sequence_id); @@ -65,14 +74,6 @@ private: const uint64_t new_sequence_id, common::ObISQLClient &sql_client, ObIAllocator &allocator); - int alter_sequence_start_with(const ObSequenceSchema &sequence_schema, - common::ObISQLClient &sql_client); - int get_sequence_sync_value(const uint64_t tenant_id, - const uint64_t sequence_id, - common::ObISQLClient &sql_client, - ObIAllocator &allocator, - common::number::ObNumber &next_value); - int clean_sequence_cache(uint64_t tenant_id, uint64_t sequence_id); private: DISALLOW_COPY_AND_ASSIGN(ObSequenceSqlService); }; diff --git a/src/share/schema/ob_table_sql_service.cpp b/src/share/schema/ob_table_sql_service.cpp index 8a131caff..70e6e1ce3 100644 --- a/src/share/schema/ob_table_sql_service.cpp +++ b/src/share/schema/ob_table_sql_service.cpp @@ -713,6 +713,61 @@ int ObTableSqlService::truncate_subpart_info( return ret; } +int ObTableSqlService::exchange_part_info( + common::ObISQLClient &sql_client, + const ObTableSchema &ori_table, + ObTableSchema &inc_table, + ObTableSchema &del_table, + const int64_t schema_version) +{ + int ret = OB_SUCCESS; + bool is_truncate_table = false; + bool is_truncate_partition = true; + if (OB_FAIL(check_ddl_allowed(ori_table))) { + LOG_WARN("check ddl allowd failed", K(ret), K(ori_table)); + } else if (OB_FAIL(drop_inc_part_info(sql_client, + ori_table, + del_table, + schema_version, + is_truncate_partition, + is_truncate_table))) { + LOG_WARN("delete inc part info failed", K(ret)); + } else if (OB_FAIL(add_inc_partition_info(sql_client, + ori_table, + inc_table, + schema_version, + true/*is_truncate_table*/, + false/*is_subpart*/))) { + LOG_WARN("add inc part info failed", K(ret)); + } + return ret; +} + +int ObTableSqlService::exchange_subpart_info( + common::ObISQLClient &sql_client, + const ObTableSchema &ori_table, + ObTableSchema &inc_table, + ObTableSchema &del_table, + const int64_t schema_version) +{ + int ret = OB_SUCCESS; + const ObPartition *part = NULL; + if (OB_FAIL(check_ddl_allowed(ori_table))) { + LOG_WARN("check ddl allowd failed", K(ret), K(ori_table)); + } else if (OB_FAIL(drop_inc_subpart_info(sql_client, ori_table, del_table, + schema_version))) { + LOG_WARN("failed to drop partition", K(ret), K(del_table)); + } else if (OB_FAIL(add_inc_partition_info(sql_client, + ori_table, + inc_table, + schema_version, + true/*is_truncate_table*/, + true/*is_subpart*/))) { + LOG_WARN("add partition info failed", K(ret)); + } + return ret; +} + int ObTableSqlService::drop_table(const ObTableSchema &table_schema, const int64_t new_schema_version, ObISQLClient &sql_client, diff --git a/src/share/schema/ob_table_sql_service.h b/src/share/schema/ob_table_sql_service.h index 0cbd6cc61..ab0d92677 100644 --- a/src/share/schema/ob_table_sql_service.h +++ b/src/share/schema/ob_table_sql_service.h @@ -208,6 +208,20 @@ public: ObTableSchema &del_table, const int64_t schema_version); + int exchange_part_info( + common::ObISQLClient &sql_client, + const ObTableSchema &ori_table, + ObTableSchema &inc_table, + ObTableSchema &del_table, + const int64_t schema_version); + + int exchange_subpart_info( + common::ObISQLClient &sql_client, + const ObTableSchema &ori_table, + ObTableSchema &inc_table, + ObTableSchema &del_table, + const int64_t schema_version); + int sync_schema_version_for_history( common::ObISQLClient &sql_client, ObTableSchema &schema, diff --git a/src/share/tablet/ob_tablet_to_ls_operator.cpp b/src/share/tablet/ob_tablet_to_ls_operator.cpp index e566378bb..aa6ad921e 100644 --- a/src/share/tablet/ob_tablet_to_ls_operator.cpp +++ b/src/share/tablet/ob_tablet_to_ls_operator.cpp @@ -288,6 +288,41 @@ int ObTabletToLSTableOperator::batch_update( } return ret; } +int ObTabletToLSTableOperator::update_table_to_tablet_id_mapping(common::ObISQLClient &sql_proxy, + const uint64_t tenant_id, + const uint64_t table_id, + const common::ObTabletID &tablet_id) +{ + int ret = OB_SUCCESS; + uint64_t data_version = 0; + if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || OB_INVALID_ID == table_id || !tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(tenant_id), K(tablet_id), K(tablet_id)); + } else if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, data_version))) { + LOG_WARN("fail to get min data version", KR(ret)); + } else if (data_version < DATA_VERSION_4_3_1_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("update table id and tablet id mapping when data_version is less than 4.3.1.0 is not supported", K(ret), K(table_id), K(tablet_id)); + } else { + ObSqlString sql; + ObDMLSqlSplicer dml_splicer; + int64_t affected_rows = 0; + if (OB_FAIL(dml_splicer.add_pk_column("tablet_id", tablet_id.id())) + || OB_FAIL(dml_splicer.add_column("table_id", table_id))) { + LOG_WARN("fail to add column", K(ret), K(tablet_id), K(table_id)); + } else if (OB_FAIL(dml_splicer.splice_update_sql(OB_ALL_TABLET_TO_LS_TNAME, sql))) { + LOG_WARN("fail to splice batch insert update sql", K(ret), K(sql)); + } else if (OB_FAIL(sql_proxy.write(tenant_id, sql.ptr(), affected_rows))) { + LOG_WARN("fail to write sql", K(ret), K(sql), K(affected_rows)); + } else if(!is_single_row(affected_rows)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expect one row", K(ret), K(sql), K(affected_rows)); + } else { + LOG_TRACE("update tablet_to_ls success", K(tenant_id), K(affected_rows)); + } + } + return ret; +} int ObTabletToLSTableOperator::inner_batch_update_by_sql_( common::ObISQLClient &sql_proxy, diff --git a/src/share/tablet/ob_tablet_to_ls_operator.h b/src/share/tablet/ob_tablet_to_ls_operator.h index 42661dc9c..2e9e5c6b4 100644 --- a/src/share/tablet/ob_tablet_to_ls_operator.h +++ b/src/share/tablet/ob_tablet_to_ls_operator.h @@ -133,6 +133,11 @@ public: const int64_t new_transfer_seq, const ObLSID &new_ls_id, const int32_t group_id); + static int update_table_to_tablet_id_mapping( + common::ObISQLClient &sql_proxy, + const uint64_t tenant_id, + const uint64_t table_id, + const common::ObTabletID &tablet_id); // Get rows from __all_tablet_to_ls according to ObTableIDs // // @param [in] sql_proxy, ObMySQLProxy or ObMySQLTransaction diff --git a/src/sql/engine/cmd/ob_table_executor.cpp b/src/sql/engine/cmd/ob_table_executor.cpp index 8752942d1..c88afa3de 100644 --- a/src/sql/engine/cmd/ob_table_executor.cpp +++ b/src/sql/engine/cmd/ob_table_executor.cpp @@ -900,6 +900,24 @@ int ObAlterTableExecutor::alter_table_rpc_v2( return ret; } +int ObAlterTableExecutor::alter_table_exchange_partition_rpc(obrpc::ObExchangePartitionArg &exchange_partition_arg, + obrpc::ObAlterTableRes &res, + obrpc::ObCommonRpcProxy *common_rpc_proxy, + ObSQLSessionInfo *my_session) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(my_session) || OB_ISNULL(common_rpc_proxy) || OB_UNLIKELY(!exchange_partition_arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(exchange_partition_arg.is_valid())); + } else if (OB_FAIL(common_rpc_proxy->exchange_partition(exchange_partition_arg, res))) { + LOG_WARN("rpc proxy alter table failed", K(ret), "dst", common_rpc_proxy->get_server(), K(exchange_partition_arg)); + } else { + // 在回滚时不会重试,也不检查 schema version + exchange_partition_arg.based_schema_object_infos_.reset(); + } + return ret; +} + int ObAlterTableExecutor::sort_external_files(ObIArray &file_urls, ObIArray &file_sizes) { int ret = OB_SUCCESS; @@ -1188,6 +1206,7 @@ int ObAlterTableExecutor::execute(ObExecContext &ctx, ObAlterTableStmt &stmt) ObTaskExecutorCtx *task_exec_ctx = NULL; obrpc::ObCommonRpcProxy *common_rpc_proxy = NULL; obrpc::ObAlterTableArg &alter_table_arg = stmt.get_alter_table_arg(); + obrpc::ObExchangePartitionArg &exchange_partition_arg = stmt.get_exchange_partition_arg(); LOG_DEBUG("start of alter table execute", K(alter_table_arg)); ObString first_stmt; OZ (stmt.get_first_stmt(first_stmt)); @@ -1219,6 +1238,7 @@ int ObAlterTableExecutor::execute(ObExecContext &ctx, ObAlterTableStmt &stmt) LOG_WARN("get first statement failed", K(ret)); } else { alter_table_arg.ddl_stmt_str_ = first_stmt; + exchange_partition_arg.ddl_stmt_str_ = first_stmt; my_session = ctx.get_my_session(); if (NULL == my_session) { ret = OB_ERR_UNEXPECTED; @@ -1262,13 +1282,19 @@ int ObAlterTableExecutor::execute(ObExecContext &ctx, ObAlterTableStmt &stmt) } } if (OB_SUCC(ret)) { - if (OB_FAIL(alter_table_rpc_v2( - alter_table_arg, - res, - allocator, - common_rpc_proxy, - my_session, - is_sync_ddl_user))) { + if (obrpc::ObAlterTableArg::EXCHANGE_PARTITION == alter_table_arg.alter_part_type_) { + if (OB_FAIL(alter_table_exchange_partition_rpc(exchange_partition_arg, + res, + common_rpc_proxy, + my_session))) { + LOG_WARN("Failed to alter table exchange partition rpc", K(ret), K(exchange_partition_arg)); + } + } else if (OB_FAIL(alter_table_rpc_v2(alter_table_arg, + res, + allocator, + common_rpc_proxy, + my_session, + is_sync_ddl_user))) { LOG_WARN("Failed to alter table rpc v2", K(ret)); } } @@ -1977,6 +2003,8 @@ int ObAlterTableExecutor::check_alter_partition(ObExecContext &ctx, || obrpc::ObAlterTableArg::TRUNCATE_PARTITION == arg.alter_part_type_ || obrpc::ObAlterTableArg::TRUNCATE_SUB_PARTITION == arg.alter_part_type_) { // do-nothing + } else if (obrpc::ObAlterTableArg::EXCHANGE_PARTITION == arg.alter_part_type_) { + // do-nothing } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("no operation", K(arg.alter_part_type_), K(ret)); diff --git a/src/sql/engine/cmd/ob_table_executor.h b/src/sql/engine/cmd/ob_table_executor.h index d44f6fbad..48b88b72e 100644 --- a/src/sql/engine/cmd/ob_table_executor.h +++ b/src/sql/engine/cmd/ob_table_executor.h @@ -143,6 +143,12 @@ private: ObSQLSessionInfo *my_session, const bool is_sync_ddl_user); + int alter_table_exchange_partition_rpc( + obrpc::ObExchangePartitionArg &exchange_partition_arg, + obrpc::ObAlterTableRes &res, + obrpc::ObCommonRpcProxy *common_rpc_proxy, + ObSQLSessionInfo *my_session); + int need_check_constraint_validity(obrpc::ObAlterTableArg &alter_table_arg, bool &need_check); int set_alter_col_nullable_ddl_stmt_str( diff --git a/src/sql/parser/non_reserved_keywords_mysql_mode.c b/src/sql/parser/non_reserved_keywords_mysql_mode.c index 21bf2eade..abf195360 100644 --- a/src/sql/parser/non_reserved_keywords_mysql_mode.c +++ b/src/sql/parser/non_reserved_keywords_mysql_mode.c @@ -1023,6 +1023,8 @@ static const NonReservedKeyword Mysql_none_reserved_keywords[] = {"kv_attributes", KV_ATTRIBUTES}, {"RESOURCE_POOL", RESOURCE_POOL}, {"clone", CLONE}, + {"without", WITHOUT}, + {"validation", VALIDATION}, {"_st_asmvt", _ST_ASMVT}, }; diff --git a/src/sql/parser/sql_parser_mysql_mode.y b/src/sql/parser/sql_parser_mysql_mode.y index 3052fa9e3..58ce7d2cb 100644 --- a/src/sql/parser/sql_parser_mysql_mode.y +++ b/src/sql/parser/sql_parser_mysql_mode.y @@ -363,9 +363,9 @@ END_P SET_VAR DELIMITER UNUSUAL UPGRADE USE_BLOOM_FILTER UNKNOWN USE_FRM USER USER_RESOURCES UNBOUNDED UP UNLIMITED VALID VALUE VARIANCE VARIABLES VERBOSE VERIFY VIEW VISIBLE VIRTUAL_COLUMN_ID VALIDATE VAR_POP - VAR_SAMP + VAR_SAMP VALIDATION - WAIT WARNINGS WASH WEEK WEIGHT_STRING WHENEVER WORK WRAPPER WINDOW WEAK WITH_COLUMN_GROUP + WAIT WARNINGS WASH WEEK WEIGHT_STRING WHENEVER WORK WRAPPER WINDOW WEAK WITH_COLUMN_GROUP WITHOUT X509 XA XML @@ -16078,6 +16078,10 @@ ADD PARTITION opt_partition_range_or_list merge_nodes($$, result, T_NAME_LIST, $3); malloc_non_terminal_node($$, result->malloc_pool_, T_ALTER_SUBPARTITION_TRUNCATE, 2, $$, NULL); } +| EXCHANGE PARTITION relation_name WITH TABLE relation_factor WITHOUT VALIDATION +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_ALTER_PARTITION_EXCHANGE, 2, $3, $6); +} ; opt_partition_range_or_list: @@ -21072,6 +21076,8 @@ ACCOUNT | OBJECT_ID | TRANSFER | SUM_OPNSIZE +| VALIDATION +| WITHOUT ; unreserved_keyword_special: diff --git a/src/sql/resolver/ddl/ob_alter_table_resolver.cpp b/src/sql/resolver/ddl/ob_alter_table_resolver.cpp index 318a89309..255dd4e8d 100644 --- a/src/sql/resolver/ddl/ob_alter_table_resolver.cpp +++ b/src/sql/resolver/ddl/ob_alter_table_resolver.cpp @@ -2544,6 +2544,147 @@ int ObAlterTableResolver::resolve_drop_subpartition(const ParseNode &node, return ret; } +int ObAlterTableResolver::resolve_exchange_partition(const ParseNode &node, + const ObTableSchema &orig_table_schema) +{ + int ret = OB_SUCCESS; + uint64_t tenant_data_version = 0; + ObAlterTableStmt *alter_table_stmt = get_alter_table_stmt(); + const ObPartitionLevel part_level = orig_table_schema.get_part_level(); + if (OB_UNLIKELY(T_ALTER_PARTITION_EXCHANGE != node.type_ || OB_ISNULL(node.children_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid parse tree", K(ret), K(node.type_)); + } else if (OB_UNLIKELY(2 != node.num_child_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid parse tree, num child != 2", K(ret), K(node.num_child_)); + } else if (OB_ISNULL(node.children_[0]) || OB_ISNULL(node.children_[1])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid parse tree", K(ret)); + } else if (OB_ISNULL(session_info_) || OB_ISNULL(alter_table_stmt)) { + ret = OB_NOT_INIT; + LOG_WARN("session info and alter table stmt should not be null", K(ret), KPC(session_info_), KPC(alter_table_stmt)); + } else if (OB_FAIL(GET_MIN_DATA_VERSION(session_info_->get_effective_tenant_id(), tenant_data_version))) { + LOG_WARN("get data version failed", K(ret), K(session_info_->get_effective_tenant_id()), K(tenant_data_version)); + } else if (OB_UNLIKELY(tenant_data_version < DATA_VERSION_4_3_1_0)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("data version and feature mismatch", K(ret), K(tenant_data_version)); + } else if (OB_UNLIKELY(!orig_table_schema.is_user_table())) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "alter table type"); + LOG_WARN("unsupport behavior on not user table", K(ret), K(orig_table_schema)); + } else if (OB_UNLIKELY(PARTITION_LEVEL_ZERO == part_level)) { + ret = OB_ERR_PARTITION_MGMT_ON_NONPARTITIONED; + LOG_USER_ERROR(OB_ERR_PARTITION_MGMT_ON_NONPARTITIONED); + LOG_WARN("unsupport management on non partitioned table", K(ret), K(part_level)); + } else { + const ObPartition *part = nullptr; + const ObSubPartition *subpart = nullptr; + const ObTableSchema *exchange_table_schema = NULL; + ObString exchange_table_name; + ObString exchange_db_name; + ParseNode *second_node = node.children_[1]; + ObString origin_partition_name(static_cast(node.children_[0]->str_len_), node.children_[0]->str_value_); + if (OB_FAIL(resolve_table_relation_node(second_node, + exchange_table_name, + exchange_db_name))){ + LOG_WARN("failed to resolve exchange table node", K(ret), K(exchange_table_name), K(exchange_db_name)); + } else if (lib::is_oracle_mode() && 0 != exchange_db_name.compare(session_info_->get_database_name())) { + ret = OB_TABLE_NOT_EXIST;//compatible with Oracle, reporting error table does not exist + LOG_WARN("Swapping partitions between different database tables is not supported in oracle mode", K(ret), K(lib::is_oracle_mode()), K(exchange_db_name), K(session_info_->get_database_name())); + } else if (0 == exchange_db_name.compare(session_info_->get_database_name()) && 0 == exchange_table_name.compare(orig_table_schema.get_table_name())) { + ret = OB_ERR_NONUNIQ_TABLE; + LOG_USER_ERROR(OB_ERR_NONUNIQ_TABLE, exchange_table_name.length(), exchange_table_name.ptr()); + LOG_WARN("Not unique table/alias", K(ret), K(exchange_table_name), K(exchange_db_name), K(session_info_->get_database_name()), K(orig_table_schema.get_table_name())); + } else if (OB_ISNULL(schema_checker_)) { + ret = OB_NOT_INIT; + LOG_WARN("schema_checker should not be null", K(ret)); + } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), + exchange_db_name, + exchange_table_name, + false, + exchange_table_schema))) { + if (OB_TABLE_NOT_EXIST == ret) { + LOG_USER_ERROR(OB_TABLE_NOT_EXIST, to_cstring(exchange_db_name), to_cstring(exchange_table_name)); + } + LOG_WARN("fail to get table schema", K(ret), KPC(exchange_table_schema), K(exchange_db_name), K(exchange_table_name)); + } else if (OB_ISNULL(exchange_table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not found", K(ret), KPC(exchange_table_schema), K(exchange_db_name), K(exchange_table_name)); + } else if (OB_UNLIKELY(!exchange_table_schema->is_user_table())) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "alter table type"); + LOG_WARN("unsupport behavior on not user table", K(ret), KPC(exchange_table_schema)); + } else if (OB_UNLIKELY(exchange_table_schema->is_partitioned_table())) { + ret = OB_ERR_PARTITION_EXCHANGE_PART_TABLE; + LOG_USER_ERROR(OB_ERR_PARTITION_EXCHANGE_PART_TABLE, exchange_table_name.length(), exchange_table_name.ptr()); + } else if (share::schema::ObPartitionLevel::PARTITION_LEVEL_ONE == orig_table_schema.get_part_level()) { + if (OB_FAIL(orig_table_schema.get_partition_by_name(origin_partition_name, part))) { + LOG_WARN("fail to get partition", K(ret), K(orig_table_schema), K(origin_partition_name)); + } else if (OB_ISNULL(part)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("partition not found", K(ret), K(orig_table_schema), K(origin_partition_name)); + } else { + share::schema::ObPartitionFuncType part_type = orig_table_schema.get_part_option().get_part_func_type(); + if (OB_UNLIKELY(PARTITION_FUNC_TYPE_RANGE != part_type && PARTITION_FUNC_TYPE_RANGE_COLUMNS != part_type)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("Only support exchanging range/range columns partitions currently", K(ret), K(part_type)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "Exchange partition except range/range columns"); + } + } + } else if (share::schema::ObPartitionLevel::PARTITION_LEVEL_TWO == orig_table_schema.get_part_level()) { + if (OB_FAIL(orig_table_schema.get_partition_by_name(origin_partition_name, part))) { + if (OB_UNKNOWN_PARTITION == ret) { + ret = OB_SUCCESS; + if (OB_FAIL(orig_table_schema.get_subpartition_by_name(origin_partition_name, part, subpart))) { + LOG_WARN("get subpartition by name failed", K(ret), K(orig_table_schema), K(origin_partition_name)); + } else if (OB_ISNULL(part) || OB_ISNULL(subpart)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("partition not found", K(ret), K(OB_ISNULL(part)), K(OB_ISNULL(subpart))); + } else { + share::schema::ObPartitionFuncType subpart_type = orig_table_schema.get_sub_part_option().get_part_func_type(); + if (OB_UNLIKELY(PARTITION_FUNC_TYPE_RANGE != subpart_type && PARTITION_FUNC_TYPE_RANGE_COLUMNS != subpart_type)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("Only support exchanging range/range columns partitions currently", K(ret), K(subpart_type)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "Exchange partition except range/range columns"); + } + } + } else { + LOG_WARN("fail to get partition by name", K(ret), K(orig_table_schema), K(origin_partition_name)); + } + } else { + ret = OB_ERR_EXCHANGE_COMPOSITE_PARTITION; + LOG_WARN("cannot EXCHANGE a composite partition with a non-partitioned table", K(ret), K(orig_table_schema), K(origin_partition_name)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("partition level is invalid", K(ret), K(orig_table_schema.get_part_level())); + } + if (OB_SUCC(ret)) { + obrpc::ObExchangePartitionArg exchange_partition_arg; + if (OB_FAIL(exchange_partition_arg.based_schema_object_infos_.assign(alter_table_stmt->get_alter_table_arg().based_schema_object_infos_))) { + LOG_WARN("fail to assign based_schema_object_infos", K(ret), K(alter_table_stmt->get_alter_table_arg().based_schema_object_infos_)); + } else if (OB_FAIL(exchange_partition_arg.based_schema_object_infos_.push_back(ObBasedSchemaObjectInfo(exchange_table_schema->get_table_id(), TABLE_SCHEMA, exchange_table_schema->get_schema_version())))) { + LOG_WARN("failed to add exchange table info", K(ret), KPC(exchange_table_schema)); + } else { + exchange_partition_arg.session_id_ = session_info_->get_sessid(); + exchange_partition_arg.tenant_id_ = session_info_->get_effective_tenant_id(); + exchange_partition_arg.exchange_partition_level_ = orig_table_schema.get_part_level(); + exchange_partition_arg.base_table_id_ = orig_table_schema.get_table_id(); + exchange_partition_arg.base_table_part_name_ = origin_partition_name; + exchange_partition_arg.inc_table_id_ = exchange_table_schema->get_table_id(); + exchange_partition_arg.including_indexes_ = true; + exchange_partition_arg.without_validation_ = true; + exchange_partition_arg.update_global_indexes_ = false; + exchange_partition_arg.exec_tenant_id_ = session_info_->get_effective_tenant_id(); + if (OB_FAIL(alter_table_stmt->set_exchange_partition_arg(exchange_partition_arg))) { + LOG_WARN("fail to set exchange_partition_arg", K(ret), K(exchange_partition_arg)); + } + } + } + } + return ret; +} + int ObAlterTableResolver::check_subpart_name(const ObPartition &partition, const ObSubPartition &subpartition) { @@ -4240,6 +4381,14 @@ int ObAlterTableResolver::resolve_partition_options(const ParseNode &node) } break; } + case T_ALTER_PARTITION_EXCHANGE: { + if (OB_FAIL(resolve_exchange_partition(*partition_node, *table_schema_))) { + LOG_WARN("failed to resolve exchange partition", K(ret)); + } else { + alter_table_stmt->get_alter_table_arg().alter_part_type_ = ObAlterTableArg::EXCHANGE_PARTITION; + } + break; + } default: { ret = OB_ERR_UNEXPECTED; SQL_RESV_LOG(WARN, "Unknown alter partition option %d!", diff --git a/src/sql/resolver/ddl/ob_alter_table_resolver.h b/src/sql/resolver/ddl/ob_alter_table_resolver.h index 99ef446b1..0c233e6e2 100644 --- a/src/sql/resolver/ddl/ob_alter_table_resolver.h +++ b/src/sql/resolver/ddl/ob_alter_table_resolver.h @@ -145,6 +145,8 @@ private: const share::schema::ObTableSchema &orig_table_schema); int resolve_drop_subpartition(const ParseNode &node, const share::schema::ObTableSchema &orig_table_schema); + int resolve_exchange_partition(const ParseNode &node, + const share::schema::ObTableSchema &orig_table_schema); int resolve_rename_partition(const ParseNode &node, const share::schema::ObTableSchema &orig_table_schema); int resolve_rename_subpartition(const ParseNode &node, diff --git a/src/sql/resolver/ddl/ob_alter_table_stmt.cpp b/src/sql/resolver/ddl/ob_alter_table_stmt.cpp index 600b44788..741207120 100644 --- a/src/sql/resolver/ddl/ob_alter_table_stmt.cpp +++ b/src/sql/resolver/ddl/ob_alter_table_stmt.cpp @@ -160,5 +160,14 @@ int ObAlterTableStmt::fill_session_vars(const ObBasicSessionInfo &session) { return ret; } +int ObAlterTableStmt::set_exchange_partition_arg(const obrpc::ObExchangePartitionArg &exchange_partition_arg) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(exchange_partition_arg_.assign(exchange_partition_arg))) { + SQL_RESV_LOG(WARN, "failed to assign", K(ret), K(exchange_partition_arg)); + } + return ret; +} + } //namespace sql } //namespace oceanbase diff --git a/src/sql/resolver/ddl/ob_alter_table_stmt.h b/src/sql/resolver/ddl/ob_alter_table_stmt.h index ab8c339c3..5926d19ee 100644 --- a/src/sql/resolver/ddl/ob_alter_table_stmt.h +++ b/src/sql/resolver/ddl/ob_alter_table_stmt.h @@ -111,6 +111,8 @@ public: obrpc::ObAlterTriggerArg &get_tg_arg() { return tg_arg_; } const ObTableSchema &get_alter_table_schema() const { return alter_table_arg_.alter_table_schema_; } ObTableSchema &get_alter_table_schema() { return alter_table_arg_.alter_table_schema_; } + obrpc::ObExchangePartitionArg &get_exchange_partition_arg() { return exchange_partition_arg_;} + int set_exchange_partition_arg(const obrpc::ObExchangePartitionArg &exchange_partition_arg); private: obrpc::ObAlterTableArg alter_table_arg_; bool is_comment_table_; @@ -122,6 +124,7 @@ private: ObRawExpr *transition_expr_; uint64_t alter_table_action_count_; int64_t alter_external_table_type_; + obrpc::ObExchangePartitionArg exchange_partition_arg_; }; inline int ObAlterTableStmt::set_tz_info_wrap(const common::ObTimeZoneInfoWrap &tz_info_wrap) diff --git a/src/storage/ddl/ob_ddl_change_tablet_to_table_helper.h b/src/storage/ddl/ob_ddl_change_tablet_to_table_helper.h new file mode 100644 index 000000000..381f597f3 --- /dev/null +++ b/src/storage/ddl/ob_ddl_change_tablet_to_table_helper.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_STORAGE_OB_CHANGE_TABLET_TO_TABLE_HELPER +#define OCEANBASE_STORAGE_OB_CHANGE_TABLET_TO_TABLE_HELPER + +#include "common/ob_tablet_id.h" +#include "lib/container/ob_array.h" +#include "lib/container/ob_array_serialization.h" +#include "lib/ob_define.h" +#include "share/ob_ls_id.h" + +namespace oceanbase +{ +namespace share +{ +class SCN; +} +namespace storage +{ +namespace mds +{ +struct BufferCtx; +} + +class ObChangeTabletToTableHelper final +{ +public: + static int on_register(const char* buf, + const int64_t len, + mds::BufferCtx &ctx); // 出参,将对应修改记录在Ctx中 + + static int on_replay(const char* buf, + const int64_t len, + const share::SCN &scn, // 日志scn + mds::BufferCtx &ctx); // 备机回放 +}; + +inline int ObChangeTabletToTableHelper::on_register(const char* buf, + const int64_t len, + mds::BufferCtx &ctx) +{ + int ret = OB_SUCCESS; + return ret; +} + +inline int ObChangeTabletToTableHelper::on_replay(const char* buf, + const int64_t len, + const share::SCN &scn, // 日志scn + mds::BufferCtx &ctx) +{ + int ret = OB_SUCCESS; + return ret; +} +} // namespace storage +} // namespace oceanbase +#endif \ No newline at end of file diff --git a/src/storage/multi_data_source/compile_utility/mds_register.h b/src/storage/multi_data_source/compile_utility/mds_register.h index 9af4fcda9..30ebeec0f 100644 --- a/src/storage/multi_data_source/compile_utility/mds_register.h +++ b/src/storage/multi_data_source/compile_utility/mds_register.h @@ -18,6 +18,7 @@ // inlcude those classes definations header file in below MACRO BLOCK // CAUTION: MAKE SURE your header file is as CLEAN as possible to avoid recursive dependencies! #if defined (NEED_MDS_REGISTER_DEFINE) && !defined (NEED_GENERATE_MDS_FRAME_CODE_FOR_TRANSACTION) + #include "src/storage/ddl/ob_ddl_change_tablet_to_table_helper.h" #include "src/storage/multi_data_source/compile_utility/mds_dummy_key.h" #include "src/storage/multi_data_source/mds_ctx.h" #include "src/storage/multi_data_source/test/example_user_data_define.h" @@ -118,7 +119,10 @@ _GENERATE_MDS_FRAME_CODE_FOR_TRANSACTION_(HELPER_CLASS, BUFFER_CTX_TYPE, ID, ENU 28,\ TRANSFER_DEST_PREPARE) // UNBIND_LOB_TABLET: ID = 29 for drop lob tablet when drop column instant. - // CHANGE_TABLET_TO_TABLE_MDS: ID = 30 for exchange tablet to table bind relationship after exchanging partition. + GENERATE_MDS_FRAME_CODE_FOR_TRANSACTION(::oceanbase::storage::ObChangeTabletToTableHelper,\ + ::oceanbase::storage::mds::MdsCtx,\ + 30,\ + CHANGE_TABLET_TO_TABLE_MDS) // TABLET_SPLIT: ID = 31 for auto_split. #undef GENERATE_MDS_FRAME_CODE_FOR_TRANSACTION #endif