diff --git a/mysql-test/suite/sql_sequence/alter.result b/mysql-test/suite/sql_sequence/alter.result index d4e930ebb92..10f106553e3 100644 --- a/mysql-test/suite/sql_sequence/alter.result +++ b/mysql-test/suite/sql_sequence/alter.result @@ -301,3 +301,44 @@ drop sequence s; # # End of 10.4 tests # +# +# MDEV-32350 Can't selectively restore sequences using innodb tables from +# backup +# +create sequence s2 engine=innodb; +alter table s2 discard tablespace; +SELECT NEXTVAL(s2); +ERROR HY000: Got error 194 "Tablespace is missing for a table" from storage engine InnoDB +create sequence s1 engine=innodb; +select * from s1; +next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count +1 1 9223372036854775806 1 1 1000 0 0 +flush tables s1 for export; +unlock tables; +select * from s2; +ERROR HY000: Got error 194 "Tablespace is missing for a table" from storage engine InnoDB +SELECT NEXTVAL(s2); +ERROR HY000: Got error 194 "Tablespace is missing for a table" from storage engine InnoDB +alter sequence s2 restart; +ERROR HY000: Got error 194 "Tablespace is missing for a table" from storage engine InnoDB +alter table s2 import tablespace; +select * from s2; +next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count +1 1 9223372036854775806 1 1 1000 0 0 +SELECT NEXTVAL(s2); +NEXTVAL(s2) +1 +select NEXTVAL(s1); +NEXTVAL(s1) +1 +flush table s1,s2; +select * from s1; +next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count +1001 1 9223372036854775806 1 1 1000 0 0 +select * from s2; +next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count +1001 1 9223372036854775806 1 1 1000 0 0 +drop sequence s1,s2; +# +# End of 10.5 tests +# diff --git a/mysql-test/suite/sql_sequence/alter.test b/mysql-test/suite/sql_sequence/alter.test index 015aba22af6..ffdb67186db 100644 --- a/mysql-test/suite/sql_sequence/alter.test +++ b/mysql-test/suite/sql_sequence/alter.test @@ -202,3 +202,42 @@ drop sequence s; --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-32350 Can't selectively restore sequences using innodb tables from +--echo # backup +--echo # + +--disable_ps_protocol + +create sequence s2 engine=innodb; +alter table s2 discard tablespace; +--error ER_GET_ERRNO +SELECT NEXTVAL(s2); +create sequence s1 engine=innodb; +select * from s1; +flush tables s1 for export; +--let $MYSQLD_DATADIR= `select @@datadir` +--move_file $MYSQLD_DATADIR/test/s1.cfg $MYSQLD_DATADIR/test/s2.cfg +--copy_file $MYSQLD_DATADIR/test/s1.ibd $MYSQLD_DATADIR/test/s2.ibd +unlock tables; +--error ER_GET_ERRNO +select * from s2; +--error ER_GET_ERRNO +SELECT NEXTVAL(s2); +--error ER_GET_ERRNO +alter sequence s2 restart; +alter table s2 import tablespace; +select * from s2; +SELECT NEXTVAL(s2); +select NEXTVAL(s1); +flush table s1,s2; +select * from s1; +select * from s2; +drop sequence s1,s2; + +--enable_ps_protocol + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index 92b307ff217..3803042bec5 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -367,6 +367,21 @@ int ha_sequence::external_lock(THD *thd, int lock_type) return error; } +int ha_sequence::discard_or_import_tablespace(my_bool discard) +{ + int error= file->discard_or_import_tablespace(discard); + if (!error && !discard) + { + /* Doing import table space. Read the imported values */ + if (!(error= table->s->sequence->read_stored_values(table))) + { + table->s->sequence->initialized= SEQUENCE::SEQ_READY_TO_USE; + memcpy(table->record[1], table->s->default_values, table->s->reclength); + } + } + return error; +} + /* Squence engine error deal method */ diff --git a/sql/ha_sequence.h b/sql/ha_sequence.h index 320f8e301ee..c1810ac2351 100644 --- a/sql/ha_sequence.h +++ b/sql/ha_sequence.h @@ -143,7 +143,7 @@ public: { file->unbind_psi(); } void rebind_psi() override { file->rebind_psi(); } - + int discard_or_import_tablespace(my_bool discard) override; bool auto_repair(int error) const override { return file->auto_repair(error); } int repair(THD* thd, HA_CHECK_OPT* check_opt) override diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index b1d59aac984..273a22f9292 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -529,7 +529,30 @@ int SEQUENCE::read_initial_values(TABLE *table) /* - Do the actiual reading of data from sequence table and + This class is here to allow one to use import table space on sequences +*/ + +class Silence_table_space_errors : public Internal_error_handler +{ +public: + Silence_table_space_errors() {} + ~Silence_table_space_errors() override = default; + bool handle_condition(THD *thd, + uint sql_errno, + const char* sql_state, + Sql_condition::enum_warning_level *level, + const char* msg, + Sql_condition ** cond_hdl) override + { + if (sql_errno == ER_TABLESPACE_DISCARDED || HA_ERR_TABLESPACE_MISSING) + return true; // Silence it + return false; + } +}; + + +/* + Do the actual reading of data from sequence table and update values in the sequence object. Called once from when table is opened @@ -538,14 +561,21 @@ int SEQUENCE::read_initial_values(TABLE *table) int SEQUENCE::read_stored_values(TABLE *table) { int error; + Silence_table_space_errors error_handler; + THD *thd= table->in_use; DBUG_ENTER("SEQUENCE::read_stored_values"); + thd->push_internal_handler(&error_handler); + MY_BITMAP *save_read_set= tmp_use_all_columns(table, &table->read_set); error= table->file->ha_read_first_row(table->record[0], MAX_KEY); tmp_restore_column_map(&table->read_set, save_read_set); if (unlikely(error)) { + thd->pop_internal_handler(); + if (error == HA_ERR_TABLESPACE_MISSING && thd->tablespace_op) + DBUG_RETURN(0); // Ignore error for ALTER TABLESPACE table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -553,6 +583,7 @@ int SEQUENCE::read_stored_values(TABLE *table) adjust_values(reserved_until); all_values_used= 0; + thd->pop_internal_handler(); DBUG_RETURN(0); } @@ -775,8 +806,9 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error) DBUG_RETURN(next_value(table, 1, error)); } - if (unlikely((*error= write(table, thd->variables.binlog_row_image != - BINLOG_ROW_IMAGE_MINIMAL)))) + if (unlikely((*error= write(table, + (thd->variables.binlog_row_image != + BINLOG_ROW_IMAGE_MINIMAL))))) { reserved_until= org_reserved_until; next_free_value= res_value;