mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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().)
This commit is contained in:
@ -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;
|
|||||||
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;
|
|||||||
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
|
|||||||
|
|
||||||
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;
|
|||||||
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;
|
|||||||
--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(
|
|||||||
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 @@ new_clustered_failed:
|
|||||||
|
|
||||||
/* 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(
|
|||||||
@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(
|
|||||||
& 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(
|
|||||||
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(
|
|||||||
|
|
||||||
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);
|
||||||
|
Reference in New Issue
Block a user