/** * 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 SQL #include "ob_sql_mock_schema_utils.h" #include "share/schema/ob_table_schema.h" #include "share/schema/ob_column_schema.h" #include "share/schema/ob_schema_utils.h" #include "share/schema/ob_table_param.h" #include "lib/allocator/ob_allocator.h" #include "lib/rc/context.h" #include "lib/string/ob_sql_string.h" #include "lib/thread_local/ob_tsi_factory.h" #define GET_MOCKED_TBLS(mocked_tables) \ ObSQLMockedTables* mocked_tables = GET_TSI_MULT(ObSQLMockedTables, ObSQLMockedTables::MOCKED_TABLE_IDENTIFIER); \ OB_ASSERT(NULL != mocked_tables) namespace oceanbase { namespace sql { using namespace oceanbase::common; using namespace oceanbase::share; using namespace oceanbase::share::schema; using namespace oceanbase::lib; const char* const ROWID_IDX_TABLE_NAME = "__idx__rowid_index"; uint64_t ObSQLMockSchemaUtils::get_rowid_index_table_id(const uint64_t table_id) { return (extract_pure_id(table_id) | ObSQLMockedTables::ROWID_INDEX_MASK); } void ObSQLMockSchemaUtils::pop_mock_table() { GET_MOCKED_TBLS(mocked_tables); mocked_tables->pop_mock_table_and_index(); } const ObIArray& ObSQLMockSchemaUtils::get_all_mocked_tables() { GET_MOCKED_TBLS(mocked_tables); return mocked_tables->get_table_ids(); } int ObSQLMockSchemaUtils::add_mock_index(const uint64_t table_id) { int ret = OB_SUCCESS; GET_MOCKED_TBLS(mocked_tables); const uint64_t mocked_rowid_idx_id = get_rowid_index_table_id(table_id); ObSQLMockedTables::ObMockedRowIDIndexInfo mocked_idx_info(table_id, mocked_rowid_idx_id); ret = mocked_tables->add_index(mocked_idx_info); LOG_TRACE("add mock index", K(mocked_idx_info)); return ret; } int ObSQLMockSchemaUtils::add_mock_table(const uint64_t table_id) { int ret = OB_SUCCESS; GET_MOCKED_TBLS(mocked_tables); LOG_TRACE("add mock table", K(table_id)); if (OB_FAIL(mocked_tables->add_table(table_id))) { LOG_WARN("failed to mock rowid column", K(ret)); } else if (OB_FAIL(add_mock_index(table_id))) { LOG_WARN("failed to mock rowid index", K(ret)); } return ret; } bool ObSQLMockSchemaUtils::is_mock_table(const uint64_t table_id) { GET_MOCKED_TBLS(mocked_tables); bool is_found = false; for (int i = 0; !is_found && i < mocked_tables->get_table_ids().count(); i++) { if (table_id == mocked_tables->get_table_ids().at(i)) { is_found = true; } } // for end return is_found; } bool ObSQLMockSchemaUtils::is_mock_index(const uint64_t index_id, uint64_t& base_table_id) { GET_MOCKED_TBLS(mocked_tables); bool is_found = false; base_table_id = OB_INVALID_ID; for (int i = 0; !is_found && i < mocked_tables->get_index_ids().count(); i++) { if (index_id == mocked_tables->get_index_ids().at(i).mocked_table_id_) { is_found = true; base_table_id = mocked_tables->get_index_ids().at(i).org_table_id_; } } // for end return is_found; } bool ObSQLMockSchemaUtils::is_mock_index(const uint64_t index_id) { uint64_t unused_base_table_id = OB_INVALID_ID; bool ret_bool = is_mock_index(index_id, unused_base_table_id); if (ret_bool) { OB_ASSERT(OB_INVALID_ID != unused_base_table_id); // debug } return ret_bool; } bool ObSQLMockSchemaUtils::contain_mock_index(const uint64_t table_id) { bool is_contain = false; GET_MOCKED_TBLS(mocked_tables); for (int i = 0; !is_contain && i < mocked_tables->get_index_ids().count(); i++) { if (table_id == mocked_tables->get_index_ids().at(i).org_table_id_) { is_contain = true; } } // for end return is_contain; } const char* ObSQLMockSchemaUtils::get_rowid_index_name() { const static char* ret_idx_name = "ROWID_INDEX"; return ret_idx_name; } int ObSQLMockSchemaUtils::reset_mock_table() { int ret = OB_SUCCESS; GET_MOCKED_TBLS(mocked_tables); mocked_tables->reset(); return ret; } uint64_t ObSQLMockSchemaUtils::get_baseid_from_rowid_index_id(const uint64_t mocked_index_id) { GET_MOCKED_TBLS(mocked_tables); uint64_t real_table_id = OB_INVALID_ID; for (int i = 0; OB_INVALID_ID == real_table_id && i < mocked_tables->get_index_ids().count(); i++) { if (mocked_index_id == mocked_tables->get_index_ids().at(i).mocked_table_id_) { real_table_id = mocked_tables->get_index_ids().at(i).org_table_id_; } } // for end; return real_table_id; } int ObSQLMockSchemaUtils::prepare_mocked_schemas(const common::ObIArray& mock_rowid_tables) { int ret = OB_SUCCESS; // prepare mocked schemas for (int i = 0; OB_SUCC(ret) && i < mock_rowid_tables.count(); i++) { if (OB_FAIL(add_mock_table(mock_rowid_tables.at(i)))) { LOG_WARN("failed to mock rowid column", K(ret)); } } // for end return ret; } ObSQLMockSchemaGuard::ObSQLMockSchemaGuard() { ObSQLMockSchemaUtils::reset_mock_table(); } ObSQLMockSchemaGuard::~ObSQLMockSchemaGuard() { ObSQLMockSchemaUtils::reset_mock_table(); } int ObSQLMockSchemaUtils::mock_rowid_index( const ObTableSchema* base_table_schema, const ObTableSchema*& mocked_rowid_index_schema) { int ret = OB_SUCCESS; OB_ASSERT(NULL != base_table_schema); ObIAllocator& allocator = THIS_WORKER.get_sql_arena_allocator(); const uint64_t tenant_id = base_table_schema->get_tenant_id(); ObTableSchema rowid_idx_schema; ObTableSchema* mocked_schema = NULL; if (OB_ISNULL(base_table_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null table schema", K(ret)); } else { rowid_idx_schema.set_tenant_id(tenant_id); rowid_idx_schema.set_table_id(get_rowid_index_table_id(base_table_schema->get_table_id())); rowid_idx_schema.set_database_id(base_table_schema->get_database_id()); rowid_idx_schema.set_tablespace_id(base_table_schema->get_tablespace_id()); rowid_idx_schema.set_tablegroup_id(OB_INVALID_ID); rowid_idx_schema.set_table_type(USER_INDEX); rowid_idx_schema.set_index_type(INDEX_TYPE_UNIQUE_LOCAL); rowid_idx_schema.set_index_using_type(USING_BTREE); rowid_idx_schema.set_load_type(TABLE_LOAD_TYPE_IN_DISK); rowid_idx_schema.set_def_type(TABLE_DEF_TYPE_USER); rowid_idx_schema.set_rowkey_column_num(base_table_schema->get_rowkey_column_num() + 1); rowid_idx_schema.set_index_column_num(1); rowid_idx_schema.set_replica_num(-1); rowid_idx_schema.set_autoinc_column_id(0); rowid_idx_schema.set_auto_increment(0); rowid_idx_schema.set_read_only(true); rowid_idx_schema.set_rowkey_split_pos(0); rowid_idx_schema.set_max_used_column_id(base_table_schema->get_max_used_column_id()); rowid_idx_schema.set_part_level(PARTITION_LEVEL_ZERO); rowid_idx_schema.set_create_mem_version(base_table_schema->get_create_mem_version()); rowid_idx_schema.set_schema_version(base_table_schema->get_schema_version()); rowid_idx_schema.set_block_size(OB_DEFAULT_SSTABLE_BLOCK_SIZE); rowid_idx_schema.set_progressive_merge_num(base_table_schema->get_progressive_merge_num()); rowid_idx_schema.set_table_name(ROWID_IDX_TABLE_NAME); rowid_idx_schema.set_compress_func_name(ObString::make_string("none")); rowid_idx_schema.set_is_use_bloomfilter(false); rowid_idx_schema.set_collation_type(CS_TYPE_UTF8MB4_BIN); rowid_idx_schema.set_charset_type(ObCharset::charset_type_by_coll(CS_TYPE_UTF8MB4_BIN)); rowid_idx_schema.set_data_table_id(base_table_schema->get_table_id()); rowid_idx_schema.set_index_status(INDEX_STATUS_AVAILABLE); rowid_idx_schema.set_partition_status(PARTITION_STATUS_ACTIVE); rowid_idx_schema.set_partition_schema_version(base_table_schema->get_partition_schema_version()); rowid_idx_schema.set_comment(ObString::make_string("")); rowid_idx_schema.set_locality(base_table_schema->get_locality()); rowid_idx_schema.set_previous_locality(base_table_schema->get_previous_locality()); rowid_idx_schema.set_parser_name(base_table_schema->get_parser_name()); rowid_idx_schema.set_tablet_size(base_table_schema->get_tablet_size()); rowid_idx_schema.set_pctfree(base_table_schema->get_pctfree()); // TODO set rest infomation const ObColumnSchemaV2* col_schema = NULL; const ObRowkeyInfo& rowkey_info = base_table_schema->get_rowkey_info(); uint64_t cur_rowkey_pos = 1; ObArray rowkey_column_ids; ObArray normal_column_descs; if (OB_FAIL(ObSchemaUtils::alloc_schema(allocator, rowid_idx_schema, mocked_schema))) { LOG_WARN("failed ti allocate schema", K(ret)); } else if (OB_FAIL(rowkey_info.get_column_ids(rowkey_column_ids))) { LOG_WARN("failed to get column ids", K(ret)); } else if (OB_FAIL(base_table_schema->get_column_ids_without_rowkey(normal_column_descs))) { LOG_WARN("failed to get all normal column descs", K(ret)); } else { if (OB_ISNULL(col_schema = base_table_schema->get_column_schema(OB_HIDDEN_LOGICAL_ROWID_COLUMN_ID))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("got unexpected null column schema", K(ret)); } else { ObColumnSchemaV2 tmp_column = *col_schema; tmp_column.set_rowkey_position(cur_rowkey_pos++); tmp_column.set_index_position(1); tmp_column.set_table_id(mocked_schema->get_table_id()); if (OB_FAIL(mocked_schema->add_column(tmp_column))) { LOG_WARN("failed to add column schema", K(ret)); } } for (int i = 0; OB_SUCC(ret) && i < rowkey_column_ids.count(); i++) { if (OB_ISNULL(col_schema = base_table_schema->get_column_schema(rowkey_column_ids.at(i)))) { LOG_WARN("failed to get column schema", K(ret)); } else { ObColumnSchemaV2 tmp_column = *col_schema; tmp_column.set_rowkey_position(cur_rowkey_pos++); tmp_column.set_index_position(0); tmp_column.set_table_id(mocked_schema->get_table_id()); if (OB_FAIL(mocked_schema->add_column(tmp_column))) { LOG_WARN("failed to add column schema", K(ret)); } } } // for end for (int i = 0; OB_SUCC(ret) && i < normal_column_descs.count(); i++) { if (OB_HIDDEN_LOGICAL_ROWID_COLUMN_ID == normal_column_descs.at(i).col_id_) { // do nothing } else if (OB_ISNULL(col_schema = base_table_schema->get_column_schema(normal_column_descs.at(i).col_id_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null column schema", K(ret)); } else { ObColumnSchemaV2 tmp_column = *col_schema; tmp_column.set_index_position(0); tmp_column.set_table_id(mocked_schema->get_table_id()); if (OB_FAIL(mocked_schema->add_column(tmp_column))) { LOG_WARN("failed to add column schema", K(ret)); } } } } } if (OB_FAIL(ret)) { if (mocked_schema != NULL) { mocked_schema->~ObTableSchema(); allocator.free(mocked_schema); } } else { mocked_rowid_index_schema = mocked_schema; LOG_TRACE("get mocked rowid index", K(*mocked_schema)); } return ret; } int ObSQLMockSchemaUtils::mock_rowid_column(share::schema::ObTableSchema& table_schema) { int ret = OB_SUCCESS; bool is_rowid_exists = false; if (NULL != table_schema.get_column_schema(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME)) { is_rowid_exists = true; } if (is_virtual_table(table_schema.get_table_id()) || share::is_mysql_mode() || table_schema.is_index_table() || is_rowid_exists) { LOG_DEBUG("do not mock rowid column", K(table_schema.get_table_name_str()), K(share::is_mysql_mode()), K(table_schema.is_index_table())); } else { ObColumnSchemaV2 rowid_schema; const uint64_t tenant_id = table_schema.get_tenant_id(); const uint64_t table_id = extract_pure_id(table_schema.get_table_id()); const int64_t schema_version = table_schema.get_schema_version(); ObObj null_obj; null_obj.set_null(); rowid_schema.set_tenant_id(tenant_id); if (OB_INVALID_ID == table_id || 0 == table_id || OB_SYS_TENANT_ID == tenant_id) { rowid_schema.set_table_id(table_id); } else { rowid_schema.set_table_id(combine_id(tenant_id, table_id)); } rowid_schema.set_column_id(OB_HIDDEN_LOGICAL_ROWID_COLUMN_ID); rowid_schema.set_rowkey_position(0); rowid_schema.set_index_position(0); rowid_schema.set_tbl_part_key_pos(0); rowid_schema.set_data_type(ObURowIDType); rowid_schema.set_data_length(OB_MAX_USER_ROW_KEY_LENGTH); rowid_schema.set_data_precision(-1); rowid_schema.set_zero_fill(false); rowid_schema.set_nullable(true); rowid_schema.set_autoincrement(false); rowid_schema.set_is_hidden(true); rowid_schema.set_on_update_current_timestamp(false); rowid_schema.set_order_in_rowkey(ASC); // what this column means? rowid_schema.set_collation_type(CS_TYPE_BINARY); rowid_schema.set_charset_type(ObCharset::charset_type_by_coll(CS_TYPE_BINARY)); rowid_schema.set_schema_version(schema_version); rowid_schema.set_column_name(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME); rowid_schema.set_comment(""); rowid_schema.set_column_flags(0); rowid_schema.set_orig_default_value(null_obj); rowid_schema.set_cur_default_value(null_obj); rowid_schema.set_orig_default_value_v2(null_obj); rowid_schema.set_cur_default_value_v2(null_obj); if (OB_FAIL(table_schema.add_column(rowid_schema))) { LOG_ERROR("failed to add rowid column", K(ret)); } else { LOG_TRACE( "mocked rowid column", K(table_schema.get_column_schema(OB_HIDDEN_LOGICAL_ROWID_COLUMN_ID)), K(table_schema)); } } return ret; } } // end namespace sql } // end namespace oceanbase