polardbxengine/storage/innobase/dict/dict0upgrade.cc

1487 lines
50 KiB
C++

/*****************************************************************************
Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License, version 2.0, as published by the
Free Software Foundation.
This program is also distributed with certain software (including but not
limited to OpenSSL) that is licensed under separate terms, as designated in a
particular file or component or in included license documentation. The authors
of MySQL hereby grant you an additional permission to link the program and
your derivative works with the separately licensed software that they have
included with MySQL.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include "dict0upgrade.h"
#include <sql_backup_lock.h>
#include <sql_class.h>
#include <sql_show.h>
#include <sql_table.h>
#include <sql_tablespace.h>
#include <regex>
#include "dict0boot.h"
#include "dict0crea.h"
#include "dict0dd.h"
#include "dict0dict.h"
#include "dict0load.h"
#include "ha_innodb.h"
#include "ha_innopart.h"
#include "row0sel.h"
#include "srv0start.h"
/* This is used only during upgrade. We don't use ids
from DICT_HDR during upgrade because unlike bootstrap case,
the ids are moved after user table creation. Since we
want to create dictionary tables with fixed ids, we use
in-memory counter for upgrade */
uint32_t dd_upgrade_indexes_num = 1;
/** Vector of tables that have FTS indexes. Used for
reverting from 8.0 format FTS AUX table names to
5.7 FTS AUX table names */
static std::vector<std::string> tables_with_fts;
/** Fill foreign key information from InnoDB table to
server table
@param[in] ib_table InnoDB table object
@param[in,out] dd_table DD table object
@return false on success, otherwise true */
static bool dd_upgrade_table_fk(dict_table_t *ib_table, dd::Table *dd_table) {
for (dict_foreign_set::iterator it = ib_table->foreign_set.begin();
it != ib_table->foreign_set.end(); ++it) {
dict_foreign_t *foreign = *it;
/* Set the foreign_key name. */
dd::Foreign_key *fk_obj = dd_table->add_foreign_key();
/* Check if the foreign key name is valid */
if (innobase_check_identifier_length(strchr(foreign->id, '/') + 1)) {
ib::error(ER_IB_MSG_229)
<< "Foreign key name:" << foreign->id
<< " is too long, for the table:" << dd_table->name()
<< ". Please ALTER the foreign key name to use less"
" than 64 characters and try upgrade again.\n";
return true;
}
/* Ignore the schema name prefixed with the foreign_key name */
if (strchr(foreign->id, '/'))
fk_obj->set_name(strchr(foreign->id, '/') + 1);
else
fk_obj->set_name(foreign->id);
/* Don't set unique constraint name, it will be set by SQL-layer later. */
/* Set match option. Unused for InnoDB */
fk_obj->set_match_option(dd::Foreign_key::OPTION_NONE);
/* Set Update rule */
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
fk_obj->set_update_rule(dd::Foreign_key::RULE_CASCADE);
} else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
fk_obj->set_update_rule(dd::Foreign_key::RULE_SET_NULL);
} else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
fk_obj->set_update_rule(dd::Foreign_key::RULE_NO_ACTION);
} else {
fk_obj->set_update_rule(dd::Foreign_key::RULE_RESTRICT);
}
/* Set delete rule */
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
fk_obj->set_delete_rule(dd::Foreign_key::RULE_CASCADE);
} else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
fk_obj->set_delete_rule(dd::Foreign_key::RULE_SET_NULL);
} else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
fk_obj->set_delete_rule(dd::Foreign_key::RULE_NO_ACTION);
} else {
fk_obj->set_delete_rule(dd::Foreign_key::RULE_RESTRICT);
}
/* Set catalog name */
fk_obj->set_referenced_table_catalog_name("def");
/* Set refernced table schema name */
char db_buf[MAX_FULL_NAME_LEN + 1];
char tbl_buf[MAX_FULL_NAME_LEN + 1];
dd_parse_tbl_name(foreign->referenced_table_name, db_buf, tbl_buf, nullptr,
nullptr, nullptr);
fk_obj->set_referenced_table_schema_name(db_buf);
fk_obj->set_referenced_table_name(tbl_buf);
/* Set referencing columns */
for (uint32_t i = 0; i < foreign->n_fields; i++) {
dd::Foreign_key_element *fk_col_obj = fk_obj->add_element();
const char *foreign_col = foreign->foreign_col_names[i];
ut_ad(foreign_col != NULL);
const dd::Column *column = dd_table->get_column(
dd::String_type(foreign_col, strlen(foreign_col)));
ut_ad(column != NULL);
fk_col_obj->set_column(column);
const char *referenced_col = foreign->referenced_col_names[i];
ut_ad(referenced_col != NULL);
DBUG_EXECUTE_IF("dd_upgrade",
ib::info(ER_IB_MSG_230)
<< "FK on table: " << ib_table->name
<< " col: " << foreign_col << " references col: "
<< " of table: " << foreign->referenced_table_name;);
fk_col_obj->referenced_column_name(
dd::String_type(referenced_col, strlen(referenced_col)));
}
DBUG_EXECUTE_IF(
"dd_upgrade", ib::info(ER_IB_MSG_231)
<< "foreign name: " << foreign->id;
ib::info(ER_IB_MSG_232) << " foreign fields: " << foreign->n_fields;
ib::info(ER_IB_MSG_233) << " foreign type: " << foreign->type;
ib::info(ER_IB_MSG_234)
<< " foreign table name: " << foreign->foreign_table_name;
ib::info(ER_IB_MSG_235)
<< " referenced table name: " << foreign->referenced_table_name;
ib::info(ER_IB_MSG_236)
<< " foreign index: " << foreign->foreign_index->name;
ib::info(ER_IB_MSG_237)
<< " foreign table: " << foreign->foreign_index->table->name;);
}
return false;
}
/** Get Server Tablespace object for a InnoDB table. The tablespace is
acquired with MDL and for modification, so the caller can update the
dd::Tablespace object returned.
@param[in] thd server thread object
@param[in,out] dd_client dictionary client to retrieve tablespace
object
@param[in] ib_table InnoDB table
@return dd::Tablespace object or nullptr */
static dd::Tablespace *dd_upgrade_get_tablespace(
THD *thd, dd::cache::Dictionary_client *dd_client, dict_table_t *ib_table) {
char name[MAX_FULL_NAME_LEN + 1];
dd::Tablespace *ts_obj = nullptr;
ut_ad(ib_table->space != SPACE_UNKNOWN);
ut_ad(ib_table->space != SYSTEM_TABLE_SPACE);
if (dict_table_is_file_per_table(ib_table)) {
std::string tablespace_name;
dd_filename_to_spacename(ib_table->name.m_name, &tablespace_name);
strncpy(name, tablespace_name.c_str(), MAX_FULL_NAME_LEN);
} else {
ut_ad(DICT_TF_HAS_SHARED_SPACE(ib_table->flags));
if (ib_table->tablespace == NULL) return (ts_obj);
strncpy(name, ib_table->tablespace(), MAX_FULL_NAME_LEN);
}
DBUG_EXECUTE_IF("dd_upgrade", ib::info(ER_IB_MSG_238)
<< "The derived tablespace name is: "
<< name;);
/* MDL on tablespace name */
if (dd_tablespace_get_mdl(name)) {
ut_a(false);
}
/* For file per table tablespaces and general tablespaces, we will get
the tablespace object and then get space_id. */
if (dd_client->acquire_for_modification(name, &ts_obj)) {
ut_a(false);
}
return (ts_obj);
}
/** Get field from Server table object
@param[in] srv_table server table object
@param[in] name Field name
@return field object if found or null on failure. */
static Field *dd_upgrade_get_field(const TABLE *srv_table, const char *name) {
for (uint i = 0; i < srv_table->s->fields; i++) {
Field *field = srv_table->field[i];
if (strcmp(field->field_name, name) == 0) {
return (field);
}
}
return (nullptr);
}
/** Return true if table has primary key given by user else false
@param[in] dd_table Server table object
@retval true Table has PK given by user
@retval false Primary Key is hidden and generated */
static bool dd_has_explicit_pk(const dd::Table *dd_table) {
return (!dd_table->indexes().front()->is_hidden());
}
/** Match InnoDB column object and Server column object
@param[in] field Server field object
@param[in] col InnoDB column object
@retval false column definition matches
@retval true column definition mismatch */
static bool dd_upgrade_match_single_col(const Field *field,
const dict_col_t *col) {
ulint unsigned_type;
ulint col_type = get_innobase_type_from_mysql_type(&unsigned_type, field);
bool failure = false;
DBUG_EXECUTE_IF("dd_upgrade_strict_mode", ut_ad(col->mtype == col_type););
if (col->mtype != col_type) {
ib::error(ER_IB_MSG_239)
<< "Column datatype mismatch for col: " << field->field_name;
failure = true;
}
ulint nulls_allowed = field->real_maybe_null() ? 0 : DATA_NOT_NULL;
ulint binary_type = field->binary() ? DATA_BINARY_TYPE : 0;
ulint charset_no = 0;
if (dtype_is_string_type(col_type)) {
charset_no = (ulint)field->charset()->number;
if (charset_no > MAX_CHAR_COLL_NUM) {
ib::error(ER_IB_MSG_240)
<< "In InnoDB, charset-collation codes"
<< " must be below 256. Unsupported code " << charset_no;
DBUG_EXECUTE_IF("dd_upgrade_strict_mode", bool invalid_collation = true;
ut_ad(!invalid_collation););
failure = true;
}
}
ulint col_len = field->pack_length();
/* The MySQL pack length contains 1 or 2 bytes length field
for a true VARCHAR. Let us subtract that, so that the InnoDB
column length in the InnoDB data dictionary is the real
maximum byte length of the actual data. */
ulint long_true_varchar = 0;
if (field->type() == MYSQL_TYPE_VARCHAR) {
col_len -= ((Field_varstring *)field)->length_bytes;
if (((Field_varstring *)field)->length_bytes == 2) {
long_true_varchar = DATA_LONG_TRUE_VARCHAR;
}
}
if (col_type == DATA_POINT) {
col_len = DATA_POINT_LEN;
}
ulint is_virtual = (innobase_is_v_fld(field)) ? DATA_VIRTUAL : 0;
ulint server_prtype =
(static_cast<ulint>(field->type()) | nulls_allowed | unsigned_type |
binary_type | long_true_varchar | is_virtual);
/* First two bytes store charset, last two bytes store precision
value. Get the last two bytes. i.e precision value */
ulint innodb_prtype = (col->prtype & 0x0000FFFF);
if (server_prtype != innodb_prtype) {
ib::error(ER_IB_MSG_241)
<< "Column precision type mismatch(i.e NULLs, SIGNED/UNSIGNED "
"etc) for col: "
<< field->field_name;
failure = true;
}
/* Numeric columns from 5.1 might have charset as my_charset_bin
while 5.5+ will have charset as my_charset_latin1. Compare charsets
only if field supports character set. */
if (field->has_charset()) {
ulint col_charset = col->prtype >> 16;
if (charset_no != col_charset) {
ib::error(ER_IB_MSG_242)
<< "Column character set mismatch for col: " << field->field_name;
failure = true;
}
}
DBUG_EXECUTE_IF("dd_upgrade_strict_mode", ut_ad(col->len == col_len););
if (col_len != col->len) {
ib::error(ER_IB_MSG_243)
<< "Column length mismatch for col: " << field->field_name;
failure = true;
}
return (failure);
}
/* Match defintion of all columns in InnoDB table and DD table
@param[in] srv_table Server table object
@param[in] dd_table New DD table object
@param[in] ib_table InnoDB table object
@retval true failure
@retval false success, all columns matched */
static bool dd_upgrade_match_cols(const TABLE *srv_table,
const dd::Table *dd_table,
const dict_table_t *ib_table) {
uint32_t innodb_num_cols = ib_table->n_t_cols;
bool has_explicit_pk = dd_has_explicit_pk(dd_table);
if (has_explicit_pk) {
/* Even when there is explicit PK, InnoDB registers DB_ROW_ID
in list of columns. It is unused though. */
innodb_num_cols = innodb_num_cols - 1 /* DB_ROW_ID */;
}
if (innodb_num_cols != dd_table->columns().size()) {
ib::error(ER_IB_MSG_244)
<< "table: " << dd_table->name() << " has "
<< dd_table->columns().size() << " columns but InnoDB dictionary"
<< " has " << innodb_num_cols << " columns";
DBUG_EXECUTE_IF("dd_upgrade_strict_mode", bool columns_num_mismatch = true;
ut_ad(!columns_num_mismatch););
return (true);
}
/* Match columns */
uint32_t idx = 0;
uint32_t v_idx = 0;
for (const dd::Column *col_obj : dd_table->columns()) {
dict_col_t *ib_col = nullptr;
const char *ib_col_name = nullptr;
if (col_obj->is_virtual()) {
dict_v_col_t *v_col = dict_table_get_nth_v_col(ib_table, v_idx);
ib_col = &v_col->m_col;
ib_col_name = dict_table_get_v_col_name(ib_table, v_idx);
++v_idx;
} else {
ib_col_name = ib_table->get_col_name(idx);
if (has_explicit_pk && strcmp(ib_col_name, "DB_ROW_ID") == 0) {
++idx;
}
ib_col = ib_table->get_col(idx);
ib_col_name = ib_table->get_col_name(idx);
++idx;
}
if (strcmp(ib_col_name, col_obj->name().c_str()) == 0) {
/* Skip matching hidden fields like DB_ROW_ID, DB_TRX_ID because
these don't exist in TABLE* object of server. */
if (!col_obj->is_se_hidden()) {
/* Match col object and field */
Field *field = dd_upgrade_get_field(srv_table, ib_col_name);
ut_ad(field != NULL);
ut_ad(ib_col != NULL);
bool failure = dd_upgrade_match_single_col(field, ib_col);
if (failure) {
ib::error(ER_IB_MSG_245) << "Column " << col_obj->name()
<< " for table: " << ib_table->name
<< " mismatches with InnoDB Dictionary";
DBUG_EXECUTE_IF("dd_upgrade_strict_mode", bool column_mismatch = true;
ut_ad(!column_mismatch););
return (true);
}
}
} else {
ib::error(ER_IB_MSG_246)
<< "Column name mismatch: From InnoDB: " << ib_col_name
<< " From Server: " << col_obj->name();
DBUG_EXECUTE_IF("dd_upgrade_strict_mode",
bool column_name_mismatch = true;
ut_ad(!column_name_mismatch););
return (true);
}
}
#ifdef UNIV_DEBUG
uint32_t processed_columns_num = idx + v_idx;
if (has_explicit_pk) {
processed_columns_num -= 1;
}
ut_ad(processed_columns_num == dd_table->columns().size());
#endif /* UNIV_DEBUG */
return (false);
}
/** Find key number from a server table object
@param[in] srv_table server table object
@param[in] name index name
@retval UINT32_MAX if index not found, else key number */
static uint32_t dd_upgrade_find_index(TABLE *srv_table, const char *name) {
for (uint32_t i = 0; i < srv_table->s->keys; i++) {
KEY *key = srv_table->key_info + i;
if (strcmp(key->name, name) == 0) {
return (i);
}
}
return (UINT32_MAX);
}
/** Match InnoDB index definition from Server object
@param[in] srv_table Server table object
@param[in] index InnoDB index
@retval false Index definition matches
@retval true Index definition mismatch */
static bool dd_upgrade_match_index(TABLE *srv_table, dict_index_t *index) {
uint32_t key_no = dd_upgrade_find_index(srv_table, index->name);
if (key_no == UINT32_MAX) {
ib::info(ER_IB_MSG_247) << "Index: " << index->name << " exists"
<< " in InnoDB but not in Server";
DBUG_EXECUTE_IF("dd_upgrade_strict_mode", bool index_not_found = true;
ut_ad(!index_not_found););
return (true);
}
KEY *key = srv_table->key_info + key_no;
ut_ad(key != nullptr);
DBUG_EXECUTE_IF("dd_upgrade_strict_mode", ut_ad(key->user_defined_key_parts ==
index->n_user_defined_cols););
if (key->user_defined_key_parts != index->n_user_defined_cols) {
ib::error(ER_IB_MSG_248)
<< "The number of fields in index " << index->name
<< " according to Server: " << key->user_defined_key_parts
<< " according to InnoDB: " << index->n_user_defined_cols;
return (true);
}
ulint ind_type = 0;
if (key_no == srv_table->s->primary_key) {
ind_type |= DICT_CLUSTERED;
}
if (key->flags & HA_NOSAME) {
ind_type |= DICT_UNIQUE;
}
if (key->flags & HA_SPATIAL) {
ind_type |= DICT_SPATIAL;
}
if (key->flags & HA_FULLTEXT) {
ind_type |= DICT_FTS;
}
ulint nulls_equal = (key->flags & HA_NULL_ARE_EQUAL) ? true : false;
DBUG_EXECUTE_IF("dd_upgrade_strict_mode",
ut_ad(nulls_equal == index->nulls_equal););
if (nulls_equal != index->nulls_equal) {
ib::error(ER_IB_MSG_249) << "In index: " << index->name
<< " NULL equal from Server: " << nulls_equal
<< " From InnoDB: " << index->nulls_equal;
return (true);
}
for (ulint i = 0; i < key->user_defined_key_parts; i++) {
KEY_PART_INFO *key_part = key->key_part + i;
Field *field = srv_table->field[key_part->field->field_index];
if (field == NULL) ut_error;
const char *field_name = key_part->field->field_name;
dict_field_t *idx_field = index->get_field(i);
DBUG_EXECUTE_IF("dd_upgrade_strict_mode",
ut_ad(strcmp(field_name, idx_field->name()) == 0););
if (strcmp(field_name, idx_field->name()) != 0) {
ib::error(ER_IB_MSG_250)
<< "In index: " << index->name
<< " field name mismatches: from server: " << field_name
<< " from InnoDB: " << idx_field->name();
return (true);
}
ulint is_unsigned;
ulint col_type =
get_innobase_type_from_mysql_type(&is_unsigned, key_part->field);
ulint prefix_len;
if (DATA_LARGE_MTYPE(col_type) ||
(key_part->length < field->pack_length() &&
field->type() != MYSQL_TYPE_VARCHAR) ||
(field->type() == MYSQL_TYPE_VARCHAR &&
key_part->length <
field->pack_length() - ((Field_varstring *)field)->length_bytes)) {
switch (col_type) {
default:
prefix_len = key_part->length;
break;
case DATA_INT:
case DATA_FLOAT:
case DATA_DOUBLE:
case DATA_DECIMAL:
prefix_len = 0;
}
} else {
prefix_len = 0;
}
if (!(index->type & (DICT_FTS | DICT_SPATIAL))) {
if (prefix_len != index->get_field(i)->prefix_len) {
ib::error(ER_IB_MSG_251)
<< "In Index: " << index->name
<< " prefix_len mismatches: from server: " << prefix_len
<< " from InnoDB: " << index->get_field(i)->prefix_len;
DBUG_EXECUTE_IF("dd_upgrade_strict_mode",
ut_ad(prefix_len == index->get_field(i)->prefix_len););
return (true);
}
}
if (innobase_is_v_fld(key_part->field)) {
ind_type |= DICT_VIRTUAL;
}
}
DBUG_EXECUTE_IF("dd_upgrade_strict_mode", ut_ad(index->type == ind_type););
if (index->type != ind_type) {
ib::error(ER_IB_MSG_252) << "Index name: " << index->name
<< " type mismatches: from server: " << ind_type
<< " from InnoDB: " << index->type;
return (true);
}
return (false);
}
/* Check if the table has auto inc field
@param[in] srv_tabl server table object
@param[in,out] auto_inc_index_name Index name on which auto inc exists
@param[in,out] auto_inc_col_name Column name of the auto inc field
@retval true if auto inc field exists
@retval false if auot inc field doesn't exist */
static bool dd_upgrade_check_for_autoinc(TABLE *srv_table,
const char *&auto_inc_index_name,
const char *&auto_inc_col_name) {
if (srv_table->s->found_next_number_field) {
const Field *field = *srv_table->s->found_next_number_field;
KEY *key;
key = srv_table->s->key_info + srv_table->s->next_number_index;
auto_inc_index_name = key->name;
auto_inc_col_name = field->field_name;
DBUG_EXECUTE_IF("dd_upgrade", ib::info(ER_IB_MSG_253)
<< "Index with auto_increment "
<< key->name;);
if (auto_inc_index_name == nullptr || auto_inc_col_name == nullptr) {
return (false);
} else {
return (true);
}
} else {
auto_inc_index_name = nullptr;
auto_inc_col_name = nullptr;
return (false);
}
}
/** Set auto-inc field value in dd::Table object
@param[in] srv_table server table object
@param[in,out] dd_table dd table object to be filled
@param[in,out] auto_inc_value auto_inc value */
static void dd_upgrade_set_auto_inc(const TABLE *srv_table, dd::Table *dd_table,
uint64_t auto_inc_value) {
ulonglong col_max_value;
const Field *field = *srv_table->s->found_next_number_field;
col_max_value = field->get_max_int_value();
/* At the this stage we do not know the increment
nor the offset, so use a default increment of 1. */
auto_inc_value =
innobase_next_autoinc(auto_inc_value, 1, 1, 0, col_max_value);
dd::Properties &table_properties = dd_table->se_private_data();
dd_set_autoinc(table_properties, auto_inc_value);
}
/* Set DD Index se_private_data and also read auto_inc if it the index
matches with auto_inc index name
@param[in,out] dd_index dd::Index object
@param[in] index InnoDB index object
@param[in] dd_space_id Server space id for index
(not InnoDB space id)
@param[in] has_auto_inc true if table has auto inc field
@param[in] auto_inc_index_name Index name on which auto_inc exists
@param[in] auto_inc_col_name col name on which auto_inc exists
@param[in,out] read_auto_inc auto inc value read */
template <typename Index>
static void dd_upgrade_process_index(Index dd_index, dict_index_t *index,
dd::Object_id dd_space_id,
bool has_auto_inc,
const char *auto_inc_index_name,
const char *auto_inc_col_name,
uint64_t *read_auto_inc) {
dd_index->set_tablespace_id(dd_space_id);
dd::Properties &p = dd_index->se_private_data();
p.set(dd_index_key_strings[DD_INDEX_ROOT], index->page);
p.set(dd_index_key_strings[DD_INDEX_SPACE_ID], index->space);
p.set(dd_index_key_strings[DD_INDEX_ID], index->id);
p.set(dd_index_key_strings[DD_TABLE_ID], index->table->id);
p.set(dd_index_key_strings[DD_INDEX_TRX_ID], 0);
if (has_auto_inc) {
ut_ad(auto_inc_index_name != nullptr);
ut_ad(auto_inc_col_name != nullptr);
if (strcmp(index->name(), auto_inc_index_name) == 0) {
dberr_t err =
row_search_max_autoinc(index, auto_inc_col_name, read_auto_inc);
if (err != DB_SUCCESS) {
ut_ad(0);
}
}
}
}
/** Migrate partitions to new dictionary
@param[in] thd Server thread object
@param[in] norm_name partition table name
@param[in,out] dd_table Server new DD table object to be filled
@param[in] srv_table Server table object
@return false on success, true on error */
static bool dd_upgrade_partitions(THD *thd, const char *norm_name,
dd::Table *dd_table, TABLE *srv_table) {
char partition_name[FN_REFLEN];
size_t table_name_len;
char *partition_name_start;
strcpy(partition_name, norm_name);
table_name_len = strlen(norm_name);
partition_name_start = partition_name + table_name_len;
/* Check for auto inc */
const char *auto_inc_index_name = NULL;
const char *auto_inc_col_name = NULL;
bool has_auto_inc = dd_upgrade_check_for_autoinc(
srv_table, auto_inc_index_name, auto_inc_col_name);
uint64_t max_auto_inc = 0;
for (dd::Partition *part_obj : *dd_table->leaf_partitions()) {
size_t len = Ha_innopart_share::create_partition_postfix(
partition_name_start, FN_REFLEN - table_name_len, part_obj);
if (table_name_len + len >= FN_REFLEN) {
ut_ad(0);
}
dict_table_t *part_table = dict_table_open_on_name(
partition_name, FALSE, TRUE, DICT_ERR_IGNORE_NONE);
dict_table_close(part_table, false, false);
DBUG_EXECUTE_IF("dd_upgrade",
ib::info(ER_IB_MSG_254)
<< "Part table name from server: " << partition_name
<< " from InnoDB: " << part_table->name.m_name;);
if (DICT_TF_HAS_SHARED_SPACE(part_table->flags)) {
ib::error(ER_IB_MSG_1282)
<< "Partitioned table '" << part_table->name.m_name
<< "' is not allowed to use shared tablespace '"
<< part_table->tablespace << "'. Please move all "
<< "partitions to file-per-table tablespaces before upgrade.";
return (true);
}
/* Set table id to mysql.columns at runtime */
if (dd_part_is_first(part_obj)) {
for (auto dd_column : *dd_table->table().columns()) {
dd_column->se_private_data().set(dd_index_key_strings[DD_TABLE_ID],
part_table->id);
}
}
/* Set table id */
part_obj->set_se_private_id(part_table->id);
/* Set DATA_DIRECTORY attribute in se_private_data */
if (DICT_TF_HAS_DATA_DIR(part_table->flags)) {
ut_ad(dict_table_is_file_per_table(part_table));
part_obj->se_private_data().set(
dd_table_key_strings[DD_TABLE_DATA_DIRECTORY], true);
}
/* Set Discarded attribute in DD table se_private_data */
if (dict_table_is_discarded(part_table)) {
part_obj->se_private_data().set(dd_table_key_strings[DD_TABLE_DISCARD],
true);
}
dd::Object_id dd_space_id;
if (part_table->space == SYSTEM_TABLE_SPACE) {
dd_space_id = dict_sys_t::s_dd_sys_space_id;
/* Tables in system tablespace cannot be discarded. */
ut_ad(!dict_table_is_discarded(part_table));
} else {
dd::cache::Dictionary_client *dd_client = dd::get_dd_client(thd);
dd::cache::Dictionary_client::Auto_releaser releaser(dd_client);
dd::Tablespace *dd_space =
dd_upgrade_get_tablespace(thd, dd_client, part_table);
ut_ad(dd_space != nullptr);
if (dd_space == nullptr) {
dict_table_close(part_table, false, false);
return (true);
}
dd_space_id = dd_space->id();
/* If table is discarded, set discarded attribute in tablespace
object */
if (dict_table_is_discarded(part_table)) {
dd_tablespace_set_state(dd_space, DD_SPACE_STATE_DISCARDED);
if (dd_client->update(dd_space)) {
ut_ad(0);
}
}
}
dd_set_table_options(part_obj, part_table);
uint32_t processed_indexes_num = 0;
for (dd::Partition_index *part_index : *part_obj->indexes()) {
DBUG_EXECUTE_IF("dd_upgrade",
ib::info(ER_IB_MSG_255)
<< "Partition Index " << part_index->name()
<< " from server for table: " << part_table->name;);
for (dict_index_t *index = UT_LIST_GET_FIRST(part_table->indexes);
index != NULL; index = UT_LIST_GET_NEXT(indexes, index)) {
if (strcmp(part_index->name().c_str(), index->name()) == 0) {
uint64_t read_auto_inc = 0;
dd_upgrade_process_index(part_index, index, dd_space_id, has_auto_inc,
auto_inc_index_name, auto_inc_col_name,
&read_auto_inc);
++processed_indexes_num;
if (has_auto_inc) {
set_if_bigger(max_auto_inc, read_auto_inc);
}
break;
}
}
}
if (processed_indexes_num != part_obj->indexes()->size()) {
ib::error(ER_IB_MSG_256)
<< "Num of Indexes in InnoDB Partition doesn't match"
<< " with Indexes from server";
ib::error(ER_IB_MSG_257)
<< "Indexes from InnoDB: " << processed_indexes_num
<< " Indexes from Server: " << dd_table->indexes()->size();
return (true);
}
}
/* Set auto increment properties */
if (has_auto_inc) {
dd_upgrade_set_auto_inc(srv_table, dd_table, max_auto_inc);
}
return (false);
}
/* Set the ROW_FORMAT in dd_table based on InnoDB dictionary table
@param[in] ib_table InnoDB table
@param[in,out] dd_table Server table object */
static void dd_upgrade_set_row_type(dict_table_t *ib_table,
dd::Table *dd_table) {
if (ib_table) {
const uint32_t flags = ib_table->flags;
switch (dict_tf_get_rec_format(flags)) {
case REC_FORMAT_REDUNDANT:
dd_table->set_row_format(dd::Table::RF_REDUNDANT);
break;
case REC_FORMAT_COMPACT:
dd_table->set_row_format(dd::Table::RF_COMPACT);
break;
case REC_FORMAT_COMPRESSED:
dd_table->set_row_format(dd::Table::RF_COMPRESSED);
break;
case REC_FORMAT_DYNAMIC:
dd_table->set_row_format(dd::Table::RF_DYNAMIC);
break;
default:
ut_ad(0);
}
}
}
/** Migrate table from InnoDB Dictionary (INNODB SYS_*) tables to new Data
Dictionary. Since FTS tables contain table_id in their physical file name
and during upgrade we reserve DICT_MAX_DD_TABLES for dictionary tables.
So we rename FTS tablespace files
@param[in] thd Server thread object
@param[in] db_name database name
@param[in] table_name table name
@param[in,out] dd_table new dictionary table object to be filled
@param[in] srv_table server table object
@return false on success, true on failure. */
bool dd_upgrade_table(THD *thd, const char *db_name, const char *table_name,
dd::Table *dd_table, TABLE *srv_table) {
char norm_name[FN_REFLEN];
dict_table_t *ib_table = NULL;
/* 2 * NAME_CHAR_LEN is for dbname and tablename, 5 assumes max bytes
for charset, + 2 is for path separator and +1 is for NULL. */
char buf[2 * NAME_CHAR_LEN * 5 + 2 + 1];
bool truncated;
build_table_filename(buf, sizeof(buf), db_name, table_name, NULL, 0,
&truncated);
ut_ad(!truncated);
normalize_table_name(norm_name, buf);
bool is_part = dd_table->leaf_partitions()->size() != 0;
if (is_part) {
return (dd_upgrade_partitions(thd, norm_name, dd_table, srv_table));
}
ib_table =
dict_table_open_on_name(norm_name, FALSE, TRUE, DICT_ERR_IGNORE_NONE);
if (ib_table == NULL) {
ib::error(ER_IB_MSG_258)
<< "Table " << norm_name << " is not found in InnoDB dictionary";
return (true);
}
bool failure = dd_upgrade_match_cols(srv_table, dd_table, ib_table);
if (failure) {
dict_table_close(ib_table, false, false);
return (failure);
}
/* Set table id to mysql.columns as runtime */
for (auto dd_column : *dd_table->table().columns()) {
dd_column->se_private_data().set(dd_index_key_strings[DD_TABLE_ID],
ib_table->id);
}
dd::Object_id dd_space_id;
if (ib_table->space == SYSTEM_TABLE_SPACE) {
dd_space_id = dict_sys_t::s_dd_sys_space_id;
/* Tables in system tablespace cannot be discarded. */
ut_ad(!dict_table_is_discarded(ib_table));
} else {
dd::cache::Dictionary_client *dd_client = dd::get_dd_client(thd);
dd::cache::Dictionary_client::Auto_releaser releaser(dd_client);
dd::Tablespace *dd_space =
dd_upgrade_get_tablespace(thd, dd_client, ib_table);
if (dd_space == nullptr) {
dict_table_close(ib_table, false, false);
return (true);
}
dd_space_id = dd_space->id();
/* If table is discarded, set discarded attribute in tablespace
object */
if (dict_table_is_discarded(ib_table)) {
dd_tablespace_set_state(dd_space, DD_SPACE_STATE_DISCARDED);
if (dd_client->update(dd_space)) {
ut_ad(0);
}
}
}
dd_table->set_se_private_id(ib_table->id);
/* Set DATA_DIRECTORY attribute in se_private_data */
if (DICT_TF_HAS_DATA_DIR(ib_table->flags)) {
ut_ad(dict_table_is_file_per_table(ib_table));
dd_table->se_private_data().set(
dd_table_key_strings[DD_TABLE_DATA_DIRECTORY], true);
}
/* Set Discarded attribute in DD table se_private_data */
if (dict_table_is_discarded(ib_table)) {
dd_table->se_private_data().set(dd_table_key_strings[DD_TABLE_DISCARD],
true);
}
/* Set row_type */
dd_upgrade_set_row_type(ib_table, dd_table);
/* Check for auto inc */
const char *auto_inc_index_name = nullptr;
const char *auto_inc_col_name = nullptr;
bool has_auto_inc = dd_upgrade_check_for_autoinc(
srv_table, auto_inc_index_name, auto_inc_col_name);
uint64_t auto_inc = UINT64_MAX;
dd_set_table_options(dd_table, ib_table);
/* The number of indexes has to match. */
DBUG_EXECUTE_IF("dd_upgrade_strict_mode",
ut_ad(dd_table->indexes()->size() ==
UT_LIST_GET_LEN(ib_table->indexes)););
if (UT_LIST_GET_LEN(ib_table->indexes) != dd_table->indexes()->size()) {
ib::error(ER_IB_MSG_259) << "Num of Indexes in InnoDB doesn't match"
<< " with Indexes from server";
ib::error(ER_IB_MSG_260)
<< "Indexes from InnoDB: " << UT_LIST_GET_LEN(ib_table->indexes)
<< " Indexes from Server: " << dd_table->indexes()->size();
dict_table_close(ib_table, false, false);
return (true);
}
uint32_t processed_indexes_num = 0;
for (dd::Index *dd_index : *dd_table->indexes()) {
DBUG_EXECUTE_IF("dd_upgrade",
ib::info(ER_IB_MSG_261)
<< "Index " << dd_index->name()
<< " from server for table: " << ib_table->name;);
for (dict_index_t *index = UT_LIST_GET_FIRST(ib_table->indexes);
index != NULL; index = UT_LIST_GET_NEXT(indexes, index)) {
if (strcmp(dd_index->name().c_str(), index->name()) == 0) {
if (!dd_index->is_hidden()) {
failure = dd_upgrade_match_index(srv_table, index);
}
dd_upgrade_process_index(dd_index, index, dd_space_id, has_auto_inc,
auto_inc_index_name, auto_inc_col_name,
&auto_inc);
++processed_indexes_num;
break;
}
}
}
if (processed_indexes_num != dd_table->indexes()->size()) {
ib::error(ER_IB_MSG_262) << "Num of Indexes in InnoDB doesn't match"
<< " with Indexes from server";
ib::error(ER_IB_MSG_263)
<< "Indexes from InnoDB: " << processed_indexes_num
<< " Indexes from Server: " << dd_table->indexes()->size();
dict_table_close(ib_table, false, false);
return (true);
}
/* Set auto increment properties */
if (has_auto_inc) {
ut_ad(auto_inc != UINT64_MAX);
dd_upgrade_set_auto_inc(srv_table, dd_table, auto_inc);
ib_table->autoinc = auto_inc == 0 ? 0 : auto_inc + 1;
}
if (dict_table_has_fts_index(ib_table)) {
dberr_t err = fts_upgrade_aux_tables(ib_table);
if (err != DB_SUCCESS) {
dict_table_close(ib_table, false, false);
return (true);
} else {
mutex_enter(&dict_sys->mutex);
dict_table_prevent_eviction(ib_table);
mutex_exit(&dict_sys->mutex);
tables_with_fts.push_back(ib_table->name.m_name);
}
}
failure = failure || dd_upgrade_table_fk(ib_table, dd_table);
dict_table_close(ib_table, false, false);
return (failure);
}
/** Tablespace information required to create a
dd::Tablespace object */
typedef struct {
/** InnoDB space id */
space_id_t id;
/** Tablespace name */
const char *name;
/** Tablespace flags */
uint32_t flags;
/** Path of the tablespace file */
const char *path;
} upgrade_space_t;
/** Register InnoDB tablespace to mysql
dictionary table mysql.tablespaces
@param[in] dd_client dictionary client
@param[in] dd_space server tablespace object
@param[in] upgrade_space upgrade tablespace object
@return 0 on success, non-zero on error */
static uint32_t dd_upgrade_register_tablespace(
dd::cache::Dictionary_client *dd_client, dd::Tablespace *dd_space,
upgrade_space_t *upgrade_space) {
dd_space->set_engine(innobase_hton_name);
dd_space->set_name(upgrade_space->name);
dd::Properties &p = dd_space->se_private_data();
p.set(dd_space_key_strings[DD_SPACE_ID],
static_cast<uint32>(upgrade_space->id));
p.set(dd_space_key_strings[DD_SPACE_FLAGS],
static_cast<uint32>(upgrade_space->flags));
p.set(dd_space_key_strings[DD_SPACE_SERVER_VERSION],
DD_SPACE_CURRENT_SRV_VERSION);
p.set(dd_space_key_strings[DD_SPACE_VERSION], DD_SPACE_CURRENT_SPACE_VERSION);
dd_space_states state =
(fsp_is_undo_tablespace(upgrade_space->id) ? DD_SPACE_STATE_ACTIVE
: DD_SPACE_STATE_NORMAL);
p.set(dd_space_key_strings[DD_SPACE_STATE], dd_space_state_values[state]);
dd::Tablespace_file *dd_file = dd_space->add_file();
dd_file->set_filename(upgrade_space->path);
if (!FSP_FLAGS_GET_ENCRYPTION(upgrade_space->flags)) {
/* Update DD Option value, for Unencryption */
dd_space->options().set("encryption", "N");
} else {
/* Update DD Option value, for Encryption */
dd_space->options().set("encryption", "Y");
}
if (dd_client->store(dd_space)) {
/* It would be better to return thd->get_stmt_da()->mysql_errno(),
however, server doesn't fill in the errno during bootstrap. */
return (HA_ERR_GENERIC);
}
return (0);
}
/** Migrate tablespace entries from InnoDB SYS_TABLESPACES to new data
dictionary. FTS Tablespaces are not registered as they are handled differently.
FTS tablespaces have table_id in their name and we increment table_id of each
table by DICT_MAX_DD_TABLES.
@param[in,out] thd THD
@return MySQL error code*/
int dd_upgrade_tablespace(THD *thd) {
DBUG_TRACE;
btr_pcur_t pcur;
const rec_t *rec;
mem_heap_t *heap;
mtr_t mtr;
heap = mem_heap_create(1000);
dd::cache::Dictionary_client *dd_client = dd::get_dd_client(thd);
dd::cache::Dictionary_client::Auto_releaser releaser(dd_client);
mutex_enter(&dict_sys->mutex);
mtr_start(&mtr);
/* Pattern for matching the FTS auxiliary tablespace name which starts with
"FTS", followed by the table id. */
std::regex fts_regex("\\S+FTS_[a-f0-9]{16,16}_\\S+");
for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES); rec != NULL;
rec = dict_getnext_system(&pcur, &mtr)) {
const char *err_msg;
space_id_t space;
const char *name;
uint32_t flags;
std::string new_tablespace_name;
/* Extract necessary information from a SYS_TABLESPACES row */
err_msg = dict_process_sys_tablespaces(heap, rec, &space, &name, &flags);
mtr_commit(&mtr);
mutex_exit(&dict_sys->mutex);
std::string tablespace_name(name);
if (!err_msg && !regex_search(tablespace_name, fts_regex)) {
// Fill the dictionary object here
DBUG_EXECUTE_IF("dd_upgrade",
ib::info(ER_IB_MSG_264)
<< "Creating dictionary entry for tablespace: "
<< name;);
std::unique_ptr<dd::Tablespace> dd_space(
dd::create_object<dd::Tablespace>());
upgrade_space_t upgrade_space;
upgrade_space.id = space;
upgrade_space.flags = flags;
bool is_file_per_table = !fsp_is_system_or_temp_tablespace(space) &&
!fsp_is_shared_tablespace(flags);
std::string file_per_name;
if (is_file_per_table) {
std::string orig_tablespace_name(tablespace_name);
if ((tablespace_name.compare("mysql/innodb_table_stats") == 0) ||
(tablespace_name.find("mysql/innodb_index_stats") == 0)) {
orig_tablespace_name.append("_backup57");
}
dd_filename_to_spacename(orig_tablespace_name.c_str(),
&new_tablespace_name);
upgrade_space.name = new_tablespace_name.c_str();
} else {
upgrade_space.name = name;
}
mutex_enter(&dict_sys->mutex);
char *filename = dict_get_first_path(space);
mutex_exit(&dict_sys->mutex);
std::string orig_name(filename);
ut_free(filename);
/* To migrate statistics from 57 satistics tables, we rename the
5.7 statistics tables/tablespaces so that it doesn't conflict
with statistics table names in 8.0 */
if ((tablespace_name.compare("mysql/innodb_table_stats") == 0) ||
(tablespace_name.find("mysql/innodb_index_stats") == 0)) {
orig_name.erase(orig_name.end() - 4, orig_name.end());
orig_name.append("_backup57.ibd");
} else if (is_file_per_table) {
/* Validate whether the tablespace file exists before making
the entry in dd::tablespaces*/
mutex_enter(&dict_sys->mutex);
fil_space_t *fil_space = fil_space_get(space);
mutex_exit(&dict_sys->mutex);
/* If the file is not already opened, check for its existence
by opening it in read-only mode. */
if (fil_space == nullptr) {
Datafile df;
df.set_filepath(orig_name.c_str());
if (df.open_read_only(false) != DB_SUCCESS) {
mem_heap_free(heap);
btr_pcur_close(&pcur);
return HA_ERR_TABLESPACE_MISSING;
}
df.close();
}
}
ut_ad(filename != NULL);
upgrade_space.path = orig_name.c_str();
if (dd_upgrade_register_tablespace(dd_client, dd_space.get(),
&upgrade_space)) {
mem_heap_free(heap);
return HA_ERR_GENERIC;
}
} else {
if (err_msg != nullptr) {
push_warning_printf(thd, Sql_condition::SL_WARNING,
ER_CANT_FIND_SYSTEM_REC, "%s", err_msg);
}
}
mem_heap_empty(heap);
/* Get the next record */
mutex_enter(&dict_sys->mutex);
mtr_start(&mtr);
}
mtr_commit(&mtr);
mutex_exit(&dict_sys->mutex);
/* These are file_per_table tablespaces(created using 5.5 or
earlier). These are not found in SYS_TABLESPACES but discovered
from SYS_TABLES */
for (auto space : missing_spaces) {
std::string tablespace_name(space->name);
/* FTS tablespaces will be registered later */
if (regex_search(tablespace_name, fts_regex)) {
continue;
}
std::string new_tablespace_name;
std::unique_ptr<dd::Tablespace> dd_space(
dd::create_object<dd::Tablespace>());
upgrade_space_t upgrade_space;
upgrade_space.id = space->id;
upgrade_space.flags = space->flags;
dd_space->set_engine(innobase_hton_name);
dd_filename_to_spacename(tablespace_name.c_str(), &new_tablespace_name);
upgrade_space.name = new_tablespace_name.c_str();
Datafile df;
df.init(space->name, space->flags);
df.make_filepath(nullptr, space->name, IBD);
upgrade_space.path = df.filepath();
if (dd_upgrade_register_tablespace(dd_client, dd_space.get(),
&upgrade_space)) {
mem_heap_free(heap);
return HA_ERR_GENERIC;
}
}
mem_heap_free(heap);
return 0;
}
/** Add server version number to tablespace while upgrading.
@param[in] space_id space id of tablespace
@param[in] server_version_only leave space version unchanged
@return false on success, true on failure. */
bool upgrade_space_version(const uint32 space_id, bool server_version_only) {
buf_block_t *block;
page_t *page;
mtr_t mtr;
fil_space_t *space = fil_space_acquire(space_id);
if (space == nullptr) {
return (true);
}
const page_size_t page_size(space->flags);
mtr_start(&mtr);
block = buf_page_get(page_id_t(space_id, 0), page_size, RW_SX_LATCH, &mtr);
page = buf_block_get_frame(block);
mlog_write_ulint(page + FIL_PAGE_SRV_VERSION, DD_SPACE_CURRENT_SRV_VERSION,
MLOG_4BYTES, &mtr);
if (!server_version_only) {
mlog_write_ulint(page + FIL_PAGE_SPACE_VERSION,
DD_SPACE_CURRENT_SPACE_VERSION, MLOG_4BYTES, &mtr);
}
mtr_commit(&mtr);
fil_space_release(space);
return (false);
}
/** Add server version number to tablespace while upgrading.
@param[in] tablespace dd::Tablespace
@return false on success, true on failure. */
bool upgrade_space_version(dd::Tablespace *tablespace) {
uint32 space_id;
if (tablespace->se_private_data().get("id", &space_id)) {
/* error, attribute not found */
ut_ad(0);
return (true);
}
/* Upgrade both server and space version */
return (upgrade_space_version(space_id, false));
}
/** Upgrade innodb undo logs after upgrade. Also increment the table_id
offset by DICT_MAX_DD_TABLES. This offset increment is because the
first 256 table_ids are reserved for dictionary.
@param[in,out] thd THD
@return MySQL error code*/
int dd_upgrade_logs(THD *thd) {
int error = 0; /* return zero for success */
DBUG_TRACE;
mtr_t mtr;
mtr.start();
dict_hdr_t *dict_hdr = dict_hdr_get(&mtr);
table_id_t table_id = mach_read_from_8(dict_hdr + DICT_HDR_TABLE_ID);
DBUG_EXECUTE_IF("dd_upgrade",
ib::info(ER_IB_MSG_265)
<< "Incrementing table_id from: " << table_id << " to "
<< table_id + DICT_MAX_DD_TABLES;);
/* Increase the offset of table_id by DICT_MAX_DD_TABLES */
mlog_write_ull(dict_hdr + DICT_HDR_TABLE_ID, table_id + DICT_MAX_DD_TABLES,
&mtr);
mtr.commit();
log_buffer_flush_to_disk();
return error;
}
/** Drop all InnoDB Dictionary tables (SYS_*). This is done only at
the end of successful upgrade */
static void dd_upgrade_drop_sys_tables() {
ut_ad(srv_is_upgrade_mode);
mutex_enter(&dict_sys->mutex);
bool found;
const page_size_t page_size(
fil_space_get_page_size(SYSTEM_TABLE_SPACE, &found));
ut_ad(found);
ut_ad(page_size.equals_to(univ_page_size));
for (uint32_t i = 0; i < SYS_NUM_SYSTEM_TABLES; i++) {
dict_table_t *system_table = dict_table_get_low(SYSTEM_TABLE_NAME[i]);
ut_ad(system_table != nullptr);
ut_ad(system_table->space == SYSTEM_TABLE_SPACE);
for (dict_index_t *index = system_table->first_index(); index != nullptr;
index = index->next()) {
ut_ad(index->space == system_table->space);
const page_id_t root(index->space, index->page);
mtr_t mtr;
mtr_start(&mtr);
btr_free_if_exists(root, page_size, index->id, &mtr);
mtr_commit(&mtr);
}
dict_table_remove_from_cache(system_table);
}
dict_sys->sys_tables = nullptr;
dict_sys->sys_columns = nullptr;
dict_sys->sys_indexes = nullptr;
dict_sys->sys_fields = nullptr;
dict_sys->sys_virtual = nullptr;
mutex_exit(&dict_sys->mutex);
}
/** Drop all InnoDB stats backup tables (innodb_*_stats_backup57). This is done
* only at the end of successful upgrade */
static void dd_upgrade_drop_stats_backup_tables() {
ut_ad(srv_is_upgrade_mode);
space_id_t space_id_index_stats =
fil_space_get_id_by_name("mysql/innodb_index_stats_backup57");
space_id_t space_id_table_stats =
fil_space_get_id_by_name("mysql/innodb_table_stats_backup57");
char *index_stats_filepath = fil_space_get_first_path(space_id_index_stats);
char *table_stats_filepath = fil_space_get_first_path(space_id_table_stats);
trx_t *trx = trx_allocate_for_mysql();
if (space_id_index_stats != SPACE_UNKNOWN) {
dberr_t err;
err = fil_close_tablespace(trx, space_id_index_stats);
if (err != DB_SUCCESS) {
ib::info(ER_IB_MSG_227)
<< "dict_stats_evict_tablespace: "
<< " fil_close_tablespace(" << space_id_index_stats << ") failed! "
<< ut_strerr(err);
}
if (!fil_delete_file(index_stats_filepath)) {
ib::info(ER_IB_MSG_990)
<< "Failed to delete the datafile '" << index_stats_filepath << "'!";
}
ut_free(index_stats_filepath);
}
if (space_id_table_stats != SPACE_UNKNOWN) {
dberr_t err;
err = fil_close_tablespace(trx, space_id_table_stats);
if (err != DB_SUCCESS) {
ib::info(ER_IB_MSG_228)
<< "dict_stats_evict_tablespace: "
<< " fil_close_tablespace(" << space_id_index_stats << ") failed! "
<< ut_strerr(err);
}
if (!fil_delete_file(table_stats_filepath)) {
ib::info(ER_IB_MSG_990)
<< "Failed to delete the datafile '" << table_stats_filepath << "'!";
}
ut_free(table_stats_filepath);
}
trx_commit_for_mysql(trx);
trx_free_for_mysql(trx);
}
/** Rename back the FTS AUX tablespace names from 8.0 format to 5.7
format on upgrade failure, else mark FTS aux tables evictable
@param[in] failed_upgrade true on upgrade failure, else
false */
static void dd_upgrade_fts_rename_cleanup(bool failed_upgrade) {
for (std::string &name : tables_with_fts) {
dict_table_t *ib_table = dict_table_open_on_name(name.c_str(), FALSE, TRUE,
DICT_ERR_IGNORE_NONE);
ut_ad(ib_table != nullptr);
if (ib_table != nullptr) {
fts_upgrade_rename(ib_table, failed_upgrade);
mutex_enter(&dict_sys->mutex);
/* Do not mark the table ready for eviction if there is
a foreign key relationship on this table */
if (ib_table->foreign_set.empty() && ib_table->referenced_set.empty()) {
dict_table_allow_eviction(ib_table);
}
dict_table_close(ib_table, true, false);
mutex_exit(&dict_sys->mutex);
}
}
}
/** If upgrade is successful, this API is used to flush innodb
dirty pages to disk. In case of server crash, this function
sets storage engine for rollback any changes.
@param[in,out] thd THD
@param[in] failed_upgrade true when upgrade failed
@return MySQL error code*/
int dd_upgrade_finish(THD *thd, bool failed_upgrade) {
DBUG_TRACE;
dd_upgrade_fts_rename_cleanup(failed_upgrade);
if (failed_upgrade) {
srv_downgrade_logs = true;
} else {
/* Delete the old undo tablespaces and the references to them
in the TRX_SYS page. */
srv_undo_tablespaces_upgrade();
/* Drop InnoDB Dictionary tables (SYS_*) */
dd_upgrade_drop_sys_tables();
/* Flush entire buffer pool. */
buf_flush_sync_all_buf_pools();
/* Close and delete the backup stats tables */
dd_upgrade_drop_stats_backup_tables();
}
tables_with_fts.clear();
tables_with_fts.shrink_to_fit();
srv_is_upgrade_mode = false;
return 0;
}