Commit c407ee09 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-16145 Crash in ALTER TABLE…AUTO_INCREMENT=1 after DISCARD TABLESPACE

This is the MariaDB equivalent of fixing the MySQL 5.7 regression
Bug #26935001 ALTER TABLE AUTO_INCREMENT TRIES TO READ
INDEX FROM DISCARDED TABLESPACE

Oracle did not publish a test case, but it is easy to guess
based on the commit message. The MariaDB code is different
due to MDEV-6076 implementing persistent AUTO_INCREMENT.

commit_set_autoinc(): Report ER_TABLESPACE_DISCARDED if the
tablespace is missing.

prepare_inplace_alter_table_dict(): Avoid accessing a discarded
tablespace. (This avoids generating warnings in fil_space_acquire().)
parent 64f4576b
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
# OR DISCARDED TABLESPACES # OR DISCARDED TABLESPACES
# #
SET GLOBAL innodb_file_per_table=1; SET GLOBAL innodb_file_per_table=1;
CREATE TABLE t(a INT)ENGINE=InnoDB; CREATE TABLE t(a SERIAL)ENGINE=InnoDB;
CREATE TABLE `x..d` (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; CREATE TABLE `x..d` (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
CREATE TABLE t1(a SERIAL)ENGINE=InnoDB;
INSERT INTO t1 VALUES(1),(2),(3);
SELECT * FROM t; SELECT * FROM t;
ERROR 42S02: Table 'test.t' doesn't exist in engine ERROR 42S02: Table 'test.t' doesn't exist in engine
ALTER TABLE t ADD INDEX (a), ALGORITHM=INPLACE; ALTER TABLE t ADD INDEX (a), ALGORITHM=INPLACE;
...@@ -13,11 +15,16 @@ SHOW WARNINGS; ...@@ -13,11 +15,16 @@ SHOW WARNINGS;
Level Code Message Level Code Message
Warning 1812 Tablespace is missing for table 'test/t' Warning 1812 Tablespace is missing for table 'test/t'
Error 1932 Table 'test.t' doesn't exist in engine Error 1932 Table 'test.t' doesn't exist in engine
ALTER TABLE t1 ADD INDEX (a), ALGORITHM=COPY; ALTER TABLE t ADD INDEX (a), ALGORITHM=COPY;
ERROR 42S02: Table 'test.t1' doesn't exist ERROR 42S02: Table 'test.t' doesn't exist in engine
SHOW WARNINGS; SHOW WARNINGS;
Level Code Message Level Code Message
Error 1146 Table 'test.t1' doesn't exist Warning 1812 Tablespace is missing for table 'test/t'
Error 1932 Table 'test.t' doesn't exist in engine
ALTER TABLE t AUTO_INCREMENT=1, ALGORITHM=INPLACE;
ERROR 42S02: Table 'test.t' doesn't exist in engine
ALTER TABLE t AUTO_INCREMENT=1, ALGORITHM=COPY;
ERROR 42S02: Table 'test.t' doesn't exist in engine
ALTER TABLE t ALGORITHM=INPLACE, DISCARD TABLESPACE; ALTER TABLE t ALGORITHM=INPLACE, DISCARD TABLESPACE;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DISCARD TABLESPACE' at line 1 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DISCARD TABLESPACE' at line 1
ALTER TABLE t ALGORITHM=COPY, DISCARD TABLESPACE; ALTER TABLE t ALGORITHM=COPY, DISCARD TABLESPACE;
...@@ -32,3 +39,11 @@ DROP TABLE t; ...@@ -32,3 +39,11 @@ DROP TABLE t;
SELECT * FROM `x..d`; SELECT * FROM `x..d`;
ERROR 42S02: Table 'test.x..d' doesn't exist in engine ERROR 42S02: Table 'test.x..d' doesn't exist in engine
DROP TABLE `x..d`; DROP TABLE `x..d`;
ALTER TABLE t1 DISCARD TABLESPACE;
ALTER TABLE t1 AUTO_INCREMENT=1, ALGORITHM=INPLACE;
ERROR HY000: Tablespace has been discarded for table `t1`
ALTER TABLE t1 AUTO_INCREMENT=1, FORCE, ALGORITHM=INPLACE;
ERROR HY000: Tablespace has been discarded for table `t1`
ALTER TABLE t1 AUTO_INCREMENT=1, ALGORITHM=COPY;
ERROR HY000: Tablespace has been discarded for table `t1`
DROP TABLE t1;
...@@ -21,8 +21,10 @@ call mtr.add_suppression("Table .* in the InnoDB data dictionary has tablespace ...@@ -21,8 +21,10 @@ call mtr.add_suppression("Table .* in the InnoDB data dictionary has tablespace
let $MYSQLD_DATADIR=`select @@datadir`; let $MYSQLD_DATADIR=`select @@datadir`;
SET GLOBAL innodb_file_per_table=1; SET GLOBAL innodb_file_per_table=1;
CREATE TABLE t(a INT)ENGINE=InnoDB; CREATE TABLE t(a SERIAL)ENGINE=InnoDB;
CREATE TABLE `x..d` (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; CREATE TABLE `x..d` (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
CREATE TABLE t1(a SERIAL)ENGINE=InnoDB;
INSERT INTO t1 VALUES(1),(2),(3);
--source include/shutdown_mysqld.inc --source include/shutdown_mysqld.inc
...@@ -41,10 +43,15 @@ SELECT * FROM t; ...@@ -41,10 +43,15 @@ SELECT * FROM t;
ALTER TABLE t ADD INDEX (a), ALGORITHM=INPLACE; ALTER TABLE t ADD INDEX (a), ALGORITHM=INPLACE;
SHOW WARNINGS; SHOW WARNINGS;
--error ER_NO_SUCH_TABLE --error ER_NO_SUCH_TABLE_IN_ENGINE
ALTER TABLE t1 ADD INDEX (a), ALGORITHM=COPY; ALTER TABLE t ADD INDEX (a), ALGORITHM=COPY;
SHOW WARNINGS; SHOW WARNINGS;
--error ER_NO_SUCH_TABLE_IN_ENGINE
ALTER TABLE t AUTO_INCREMENT=1, ALGORITHM=INPLACE;
--error ER_NO_SUCH_TABLE_IN_ENGINE
ALTER TABLE t AUTO_INCREMENT=1, ALGORITHM=COPY;
--error ER_PARSE_ERROR --error ER_PARSE_ERROR
ALTER TABLE t ALGORITHM=INPLACE, DISCARD TABLESPACE; ALTER TABLE t ALGORITHM=INPLACE, DISCARD TABLESPACE;
--error ER_PARSE_ERROR --error ER_PARSE_ERROR
...@@ -56,3 +63,12 @@ DROP TABLE t; ...@@ -56,3 +63,12 @@ DROP TABLE t;
--error ER_NO_SUCH_TABLE_IN_ENGINE --error ER_NO_SUCH_TABLE_IN_ENGINE
SELECT * FROM `x..d`; SELECT * FROM `x..d`;
DROP TABLE `x..d`; DROP TABLE `x..d`;
ALTER TABLE t1 DISCARD TABLESPACE;
--error ER_TABLESPACE_DISCARDED
ALTER TABLE t1 AUTO_INCREMENT=1, ALGORITHM=INPLACE;
--error ER_TABLESPACE_DISCARDED
ALTER TABLE t1 AUTO_INCREMENT=1, FORCE, ALGORITHM=INPLACE;
--error ER_TABLESPACE_DISCARDED
ALTER TABLE t1 AUTO_INCREMENT=1, ALGORITHM=COPY;
DROP TABLE t1;
...@@ -4518,8 +4518,9 @@ prepare_inplace_alter_table_dict( ...@@ -4518,8 +4518,9 @@ prepare_inplace_alter_table_dict(
uint32_t key_id = FIL_DEFAULT_ENCRYPTION_KEY; uint32_t key_id = FIL_DEFAULT_ENCRYPTION_KEY;
fil_encryption_t mode = FIL_ENCRYPTION_DEFAULT; fil_encryption_t mode = FIL_ENCRYPTION_DEFAULT;
if (fil_space_t* space if (dict_table_is_discarded(ctx->prebuilt->table)) {
= fil_space_acquire(ctx->prebuilt->table->space)) { } else if (fil_space_t* space
= fil_space_acquire(ctx->prebuilt->table->space)) {
if (const fil_space_crypt_t* crypt_data if (const fil_space_crypt_t* crypt_data
= space->crypt_data) { = space->crypt_data) {
key_id = crypt_data->key_id; key_id = crypt_data->key_id;
...@@ -4917,7 +4918,8 @@ prepare_inplace_alter_table_dict( ...@@ -4917,7 +4918,8 @@ prepare_inplace_alter_table_dict(
/* Initialize the AUTO_INCREMENT sequence /* Initialize the AUTO_INCREMENT sequence
to the rebuilt table from the old one. */ to the rebuilt table from the old one. */
if (!old_table->found_next_number_field) { if (!old_table->found_next_number_field
|| dict_table_is_discarded(user_table)) {
} else if (ib_uint64_t autoinc } else if (ib_uint64_t autoinc
= btr_read_autoinc(clust_index)) { = btr_read_autoinc(clust_index)) {
btr_write_autoinc(new_clust_index, autoinc); btr_write_autoinc(new_clust_index, autoinc);
...@@ -7372,9 +7374,10 @@ innobase_rename_or_enlarge_columns_cache( ...@@ -7372,9 +7374,10 @@ innobase_rename_or_enlarge_columns_cache(
@param ha_alter_info Data used during in-place alter @param ha_alter_info Data used during in-place alter
@param ctx In-place ALTER TABLE context @param ctx In-place ALTER TABLE context
@param altered_table MySQL table that is being altered @param altered_table MySQL table that is being altered
@param old_table MySQL table as it is before the ALTER operation */ @param old_table MySQL table as it is before the ALTER operation
@return whether the operation failed (and my_error() was called) */
static MY_ATTRIBUTE((nonnull)) static MY_ATTRIBUTE((nonnull))
void bool
commit_set_autoinc( commit_set_autoinc(
Alter_inplace_info* ha_alter_info, Alter_inplace_info* ha_alter_info,
ha_innobase_inplace_ctx*ctx, ha_innobase_inplace_ctx*ctx,
...@@ -7402,6 +7405,13 @@ commit_set_autoinc( ...@@ -7402,6 +7405,13 @@ commit_set_autoinc(
& Alter_inplace_info::CHANGE_CREATE_OPTION) & Alter_inplace_info::CHANGE_CREATE_OPTION)
&& (ha_alter_info->create_info->used_fields && (ha_alter_info->create_info->used_fields
& HA_CREATE_USED_AUTO)) { & HA_CREATE_USED_AUTO)) {
if (dict_table_is_discarded(ctx->old_table)) {
my_error(ER_TABLESPACE_DISCARDED, MYF(0),
old_table->s->table_name.str);
DBUG_RETURN(true);
}
/* An AUTO_INCREMENT value was supplied by the user. /* An AUTO_INCREMENT value was supplied by the user.
It must be persisted to the data file. */ It must be persisted to the data file. */
const Field* ai = old_table->found_next_number_field; const Field* ai = old_table->found_next_number_field;
...@@ -7481,7 +7491,7 @@ commit_set_autoinc( ...@@ -7481,7 +7491,7 @@ commit_set_autoinc(
between prepare_inplace and commit_inplace. */ between prepare_inplace and commit_inplace. */
} }
DBUG_VOID_RETURN; DBUG_RETURN(false);
} }
/** Add or drop foreign key constraints to the data dictionary tables, /** Add or drop foreign key constraints to the data dictionary tables,
...@@ -8604,9 +8614,11 @@ ha_innobase::commit_inplace_alter_table( ...@@ -8604,9 +8614,11 @@ ha_innobase::commit_inplace_alter_table(
DBUG_ASSERT(new_clustered == ctx->need_rebuild()); DBUG_ASSERT(new_clustered == ctx->need_rebuild());
commit_set_autoinc(ha_alter_info, ctx, altered_table, table); fail = commit_set_autoinc(ha_alter_info, ctx, altered_table,
table);
if (ctx->need_rebuild()) { if (fail) {
} else if (ctx->need_rebuild()) {
ctx->tmp_name = dict_mem_create_temporary_tablename( ctx->tmp_name = dict_mem_create_temporary_tablename(
ctx->heap, ctx->new_table->name.m_name, ctx->heap, ctx->new_table->name.m_name,
ctx->new_table->id); ctx->new_table->id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment