diff --git a/mysql-test/suite/innodb/r/alter_crash.result b/mysql-test/suite/innodb/r/alter_crash.result index 77acd237218b0..6659b91522f03 100644 --- a/mysql-test/suite/innodb/r/alter_crash.result +++ b/mysql-test/suite/innodb/r/alter_crash.result @@ -243,3 +243,19 @@ a b 1 1 2 1 DROP TABLE t1; +# +# MDEV-37886 PAGE_COMPRESSED ALTER TABLE operations +# inconsistent with innodb_file_per_table setting +# +SET GLOBAL innodb_file_per_table=0; +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; +SET DEBUG_SYNC='before_lock_tables_takes_lock SIGNAL stuck WAIT_FOR go'; +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=INSTANT; +connect con1,localhost,root; +SET DEBUG_SYNC='now WAIT_FOR stuck'; +SET GLOBAL innodb_file_per_table=1; +SET DEBUG_SYNC='now SIGNAL go'; +disconnect con1; +connection default; +ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'PAGE_COMPRESSED' +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/alter_crash.test b/mysql-test/suite/innodb/t/alter_crash.test index 1829529450ddc..320befe0dba2b 100644 --- a/mysql-test/suite/innodb/t/alter_crash.test +++ b/mysql-test/suite/innodb/t/alter_crash.test @@ -241,3 +241,22 @@ CHECK TABLE t1; SHOW CREATE TABLE t1; SELECT * FROM t1; DROP TABLE t1; + +--echo # +--echo # MDEV-37886 PAGE_COMPRESSED ALTER TABLE operations +--echo # inconsistent with innodb_file_per_table setting +--echo # +SET GLOBAL innodb_file_per_table=0; +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; +SET DEBUG_SYNC='before_lock_tables_takes_lock SIGNAL stuck WAIT_FOR go'; +send ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=INSTANT; + +--connect con1,localhost,root +SET DEBUG_SYNC='now WAIT_FOR stuck'; +SET GLOBAL innodb_file_per_table=1; +SET DEBUG_SYNC='now SIGNAL go'; +--disconnect con1 +--connection default +--error ER_ILLEGAL_HA_CREATE_OPTION +--reap +DROP TABLE t1; diff --git a/sql/handler.h b/sql/handler.h index c6071bce85ae2..00d9df8d4a0ec 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2636,8 +2636,16 @@ class Alter_inplace_info /** true for ALTER IGNORE TABLE ... */ const bool ignore; - /** true for online operation (LOCK=NONE) */ - bool online= false; + /** Online operation and storage engine specific flags */ + struct + { + /** TRUE for online operation (LOCK=NONE) */ + unsigned online : 1; + /** TRUE when innodb_file_per_table is set */ + unsigned file_per_table : 1; + /** Reserved for future storage engine flags */ + unsigned reserved : 6; + } engine_flags= {0, 0, 0}; /** When ha_commit_inplace_alter_table() is called the the engine can diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 549be4faf660b..52aba56c8bf12 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7663,7 +7663,7 @@ static bool mysql_inplace_alter_table(THD *thd, switch (alter_info->requested_lock) { case Alter_info::ALTER_TABLE_LOCK_DEFAULT: case Alter_info::ALTER_TABLE_LOCK_NONE: - ha_alter_info->online= true; + ha_alter_info->engine_flags.online= true; break; case Alter_info::ALTER_TABLE_LOCK_SHARED: case Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE: @@ -10798,7 +10798,7 @@ do_continue:; thd->count_cuted_fields= CHECK_FIELD_IGNORE; if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) - ha_alter_info.online= true; + ha_alter_info.engine_flags.online= true; // Ask storage engine whether to use copy or in-place { Check_level_instant_set check_level_save(thd, CHECK_FIELD_WARN); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 43ea8c1466d19..ce8d3c8db8a9a 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -2227,6 +2227,8 @@ ha_innobase::check_if_supported_inplace_alter( { DBUG_ENTER("check_if_supported_inplace_alter"); + ha_alter_info->engine_flags.file_per_table= !!srv_file_per_table; + if ((ha_alter_info->handler_flags & INNOBASE_ALTER_VERSIONED_REBUILD) && altered_table->versioned(VERS_TIMESTAMP)) { @@ -2341,7 +2343,8 @@ ha_innobase::check_if_supported_inplace_alter( switch (ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) { case ALTER_OPTIONS: - if ((srv_file_per_table && !m_prebuilt->table->space_id) + if ((ha_alter_info->engine_flags.file_per_table && + !m_prebuilt->table->space_id) || alter_options_need_rebuild(ha_alter_info, table)) { reason_rebuild = my_get_err_msg( ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD); @@ -2532,7 +2535,7 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_ASSERT(key_part->field == altered_table -> found_next_number_field); - if (ha_alter_info->online) { + if (ha_alter_info->engine_flags.online) { ha_alter_info->unsupported_reason = my_get_err_msg( ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC); } @@ -2553,7 +2556,7 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } - if (ha_alter_info->online + if (ha_alter_info->engine_flags.online && !ha_alter_info->unsupported_reason) { ha_alter_info->unsupported_reason = MSG_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN; @@ -2749,7 +2752,7 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } - if (!online || !ha_alter_info->online + if (!online || !ha_alter_info->engine_flags.online || ha_alter_info->unsupported_reason != reason_rebuild) { /* Either LOCK=NONE was not requested, or we already gave specific reason to refuse it. */ @@ -2805,7 +2808,7 @@ ha_innobase::check_if_supported_inplace_alter( } add_fulltext = true; - if (ha_alter_info->online + if (ha_alter_info->engine_flags.online && !ha_alter_info->unsupported_reason) { ha_alter_info->unsupported_reason = my_get_err_msg( ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS); @@ -2830,7 +2833,7 @@ ha_innobase::check_if_supported_inplace_alter( if (online && (key->flags & HA_SPATIAL)) { - if (ha_alter_info->online) { + if (ha_alter_info->engine_flags.online) { ha_alter_info->unsupported_reason = my_get_err_msg( ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS); } @@ -2841,7 +2844,7 @@ ha_innobase::check_if_supported_inplace_alter( } if (m_prebuilt->table->is_stats_table()) { - if (ha_alter_info->online) { + if (ha_alter_info->engine_flags.online) { ha_alter_info->unsupported_reason = table_share->table_name.str; } @@ -2850,7 +2853,7 @@ ha_innobase::check_if_supported_inplace_alter( // FIXME: implement Online DDL for system-versioned operations if (ha_alter_info->handler_flags & INNOBASE_ALTER_VERSIONED_REBUILD) { - if (ha_alter_info->online) { + if (ha_alter_info->engine_flags.online) { ha_alter_info->unsupported_reason = not_implemented; } @@ -6600,7 +6603,7 @@ prepare_inplace_alter_table_dict( create_table_info_t info(ctx->prebuilt->trx->mysql_thd, altered_table, ha_alter_info->create_info, NULL, NULL, - srv_file_per_table); + ha_alter_info->engine_flags.file_per_table); /* The primary index would be rebuilt if a FTS Doc ID column is to be added, and the primary index definition @@ -8011,9 +8014,9 @@ ha_innobase::prepare_inplace_alter_table( This optimization is disabled for partition table. */ ha_alter_info->mdl_exclusive_after_prepare = innobase_table_is_empty(m_prebuilt->table, false); - if (ha_alter_info->online + if (ha_alter_info->engine_flags.online && ha_alter_info->mdl_exclusive_after_prepare) { - ha_alter_info->online = false; + ha_alter_info->engine_flags.online = false; } #ifdef WITH_PARTITION_STORAGE_ENGINE } @@ -8030,7 +8033,7 @@ ha_innobase::prepare_inplace_alter_table( ha_alter_info->create_info, NULL, NULL, - srv_file_per_table); + ha_alter_info->engine_flags.file_per_table); info.set_tablespace_type(indexed_table->space != fil_system.sys_space); @@ -8611,7 +8614,7 @@ ha_innobase::prepare_inplace_alter_table( drop_index, n_drop_index, drop_fk, n_drop_fk, add_fk, n_add_fk, - ha_alter_info->online, + ha_alter_info->engine_flags.online, heap, indexed_table, col_names, ULINT_UNDEFINED, 0, 0, (ha_alter_info->ignore @@ -8766,7 +8769,7 @@ ha_innobase::prepare_inplace_alter_table( m_prebuilt, drop_index, n_drop_index, drop_fk, n_drop_fk, add_fk, n_add_fk, - ha_alter_info->online, + ha_alter_info->engine_flags.online, heap, m_prebuilt->table, col_names, add_autoinc_col_no, ha_alter_info->create_info->auto_increment_value,