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

MDEV-16830 Crash in ALTER TABLE DROP FOREIGN KEY

ha_innobase::inplace_alter_table(): Do nothing if INNOBASE_ALTER_INSTANT
flags (such as DROP FOREIGN KEY) was present.

Also, use ALTER_OPTIONS instead of the alias ALTER_CHANGE_CREATE_OPTION.

This bug was caused by MDEV-11369, MDEV-13134 or related work.
parent 05459706
...@@ -446,6 +446,25 @@ ALTER TABLE t1 ADD COLUMN c INT; ...@@ -446,6 +446,25 @@ ALTER TABLE t1 ADD COLUMN c INT;
UPDATE t1 SET c = 1; UPDATE t1 SET c = 1;
UPDATE t1 SET c = 2; UPDATE t1 SET c = 2;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
CREATE TABLE t2 (b INT PRIMARY KEY, FOREIGN KEY(b) REFERENCES t1(a))
ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
INSERT INTO t1 SET a=1;
INSERT INTO t2 SET b=1;
ALTER TABLE t2 ADD COLUMN a INT, DROP FOREIGN KEY t2_ibfk_1;
ALTER TABLE t2 ADD INDEX(a);
ALTER TABLE t1 ADD COLUMN b INT, ADD FOREIGN KEY(a) REFERENCES t2(a),
ALGORITHM=INSTANT;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Adding foreign keys needs foreign_key_checks=OFF. Try ALGORITHM=COPY
SET foreign_key_checks=0;
ALTER TABLE t1 ADD COLUMN b INT, ADD FOREIGN KEY(a) REFERENCES t2(a),
ALGORITHM=INSTANT;
ALTER TABLE t2 ADD CONSTRAINT fk FOREIGN KEY(b) REFERENCES t1(a),
ALGORITHM=INSTANT;
SET foreign_key_checks=1;
ALTER TABLE t2 COMMENT 'domestic keys only', DROP FOREIGN KEY fk;
ALTER TABLE t1 DROP FOREIGN KEY t1_ibfk_1;
DROP TABLE t2, t1;
CREATE TABLE t1 CREATE TABLE t1
(id INT PRIMARY KEY, c2 INT UNIQUE, (id INT PRIMARY KEY, c2 INT UNIQUE,
c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'), c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'),
...@@ -838,6 +857,25 @@ ALTER TABLE t1 ADD COLUMN c INT; ...@@ -838,6 +857,25 @@ ALTER TABLE t1 ADD COLUMN c INT;
UPDATE t1 SET c = 1; UPDATE t1 SET c = 1;
UPDATE t1 SET c = 2; UPDATE t1 SET c = 2;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=COMPACT;
CREATE TABLE t2 (b INT PRIMARY KEY, FOREIGN KEY(b) REFERENCES t1(a))
ENGINE=InnoDB ROW_FORMAT=COMPACT;
INSERT INTO t1 SET a=1;
INSERT INTO t2 SET b=1;
ALTER TABLE t2 ADD COLUMN a INT, DROP FOREIGN KEY t2_ibfk_1;
ALTER TABLE t2 ADD INDEX(a);
ALTER TABLE t1 ADD COLUMN b INT, ADD FOREIGN KEY(a) REFERENCES t2(a),
ALGORITHM=INSTANT;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Adding foreign keys needs foreign_key_checks=OFF. Try ALGORITHM=COPY
SET foreign_key_checks=0;
ALTER TABLE t1 ADD COLUMN b INT, ADD FOREIGN KEY(a) REFERENCES t2(a),
ALGORITHM=INSTANT;
ALTER TABLE t2 ADD CONSTRAINT fk FOREIGN KEY(b) REFERENCES t1(a),
ALGORITHM=INSTANT;
SET foreign_key_checks=1;
ALTER TABLE t2 COMMENT 'domestic keys only', DROP FOREIGN KEY fk;
ALTER TABLE t1 DROP FOREIGN KEY t1_ibfk_1;
DROP TABLE t2, t1;
CREATE TABLE t1 CREATE TABLE t1
(id INT PRIMARY KEY, c2 INT UNIQUE, (id INT PRIMARY KEY, c2 INT UNIQUE,
c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'), c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'),
...@@ -1230,10 +1268,29 @@ ALTER TABLE t1 ADD COLUMN c INT; ...@@ -1230,10 +1268,29 @@ ALTER TABLE t1 ADD COLUMN c INT;
UPDATE t1 SET c = 1; UPDATE t1 SET c = 1;
UPDATE t1 SET c = 2; UPDATE t1 SET c = 2;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE TABLE t2 (b INT PRIMARY KEY, FOREIGN KEY(b) REFERENCES t1(a))
ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
INSERT INTO t1 SET a=1;
INSERT INTO t2 SET b=1;
ALTER TABLE t2 ADD COLUMN a INT, DROP FOREIGN KEY t2_ibfk_1;
ALTER TABLE t2 ADD INDEX(a);
ALTER TABLE t1 ADD COLUMN b INT, ADD FOREIGN KEY(a) REFERENCES t2(a),
ALGORITHM=INSTANT;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Adding foreign keys needs foreign_key_checks=OFF. Try ALGORITHM=COPY
SET foreign_key_checks=0;
ALTER TABLE t1 ADD COLUMN b INT, ADD FOREIGN KEY(a) REFERENCES t2(a),
ALGORITHM=INSTANT;
ALTER TABLE t2 ADD CONSTRAINT fk FOREIGN KEY(b) REFERENCES t1(a),
ALGORITHM=INSTANT;
SET foreign_key_checks=1;
ALTER TABLE t2 COMMENT 'domestic keys only', DROP FOREIGN KEY fk;
ALTER TABLE t1 DROP FOREIGN KEY t1_ibfk_1;
DROP TABLE t2, t1;
disconnect analyze; disconnect analyze;
SELECT variable_value-@old_instant instants SELECT variable_value-@old_instant instants
FROM information_schema.global_status FROM information_schema.global_status
WHERE variable_name = 'innodb_instant_alter_column'; WHERE variable_name = 'innodb_instant_alter_column';
instants instants
39 45
SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency;
...@@ -319,6 +319,27 @@ UPDATE t1 SET c = 1; ...@@ -319,6 +319,27 @@ UPDATE t1 SET c = 1;
UPDATE t1 SET c = 2; UPDATE t1 SET c = 2;
DROP TABLE t1; DROP TABLE t1;
# MDEV-16830 Crash in ALTER TABLE DROP FOREIGN KEY
eval CREATE TABLE t1 (a INT PRIMARY KEY) $engine;
eval CREATE TABLE t2 (b INT PRIMARY KEY, FOREIGN KEY(b) REFERENCES t1(a))
$engine;
INSERT INTO t1 SET a=1;
INSERT INTO t2 SET b=1;
ALTER TABLE t2 ADD COLUMN a INT, DROP FOREIGN KEY t2_ibfk_1;
ALTER TABLE t2 ADD INDEX(a);
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
ALTER TABLE t1 ADD COLUMN b INT, ADD FOREIGN KEY(a) REFERENCES t2(a),
ALGORITHM=INSTANT;
SET foreign_key_checks=0;
ALTER TABLE t1 ADD COLUMN b INT, ADD FOREIGN KEY(a) REFERENCES t2(a),
ALGORITHM=INSTANT;
ALTER TABLE t2 ADD CONSTRAINT fk FOREIGN KEY(b) REFERENCES t1(a),
ALGORITHM=INSTANT;
SET foreign_key_checks=1;
ALTER TABLE t2 COMMENT 'domestic keys only', DROP FOREIGN KEY fk;
ALTER TABLE t1 DROP FOREIGN KEY t1_ibfk_1;
DROP TABLE t2, t1;
dec $format; dec $format;
} }
disconnect analyze; disconnect analyze;
......
...@@ -77,8 +77,8 @@ static const alter_table_operations INNOBASE_DEFAULTS ...@@ -77,8 +77,8 @@ static const alter_table_operations INNOBASE_DEFAULTS
static const alter_table_operations INNOBASE_ALTER_REBUILD static const alter_table_operations INNOBASE_ALTER_REBUILD
= ALTER_ADD_PK_INDEX = ALTER_ADD_PK_INDEX
| ALTER_DROP_PK_INDEX | ALTER_DROP_PK_INDEX
| ALTER_CHANGE_CREATE_OPTION | ALTER_OPTIONS
/* CHANGE_CREATE_OPTION needs to check create_option_need_rebuild() */ /* ALTER_OPTIONS needs to check create_option_need_rebuild() */
| ALTER_COLUMN_NULLABLE | ALTER_COLUMN_NULLABLE
| INNOBASE_DEFAULTS | INNOBASE_DEFAULTS
| ALTER_STORED_COLUMN_ORDER | ALTER_STORED_COLUMN_ORDER
...@@ -498,8 +498,7 @@ static bool create_option_need_rebuild( ...@@ -498,8 +498,7 @@ static bool create_option_need_rebuild(
const Alter_inplace_info* ha_alter_info, const Alter_inplace_info* ha_alter_info,
const TABLE* table) const TABLE* table)
{ {
DBUG_ASSERT(ha_alter_info->handler_flags DBUG_ASSERT(ha_alter_info->handler_flags & ALTER_OPTIONS);
& ALTER_CHANGE_CREATE_OPTION);
if (ha_alter_info->create_info->used_fields if (ha_alter_info->create_info->used_fields
& (HA_CREATE_USED_ROW_FORMAT & (HA_CREATE_USED_ROW_FORMAT
...@@ -541,7 +540,7 @@ innobase_need_rebuild( ...@@ -541,7 +540,7 @@ innobase_need_rebuild(
{ {
if ((ha_alter_info->handler_flags & ~(INNOBASE_INPLACE_IGNORE if ((ha_alter_info->handler_flags & ~(INNOBASE_INPLACE_IGNORE
| INNOBASE_ALTER_INSTANT)) | INNOBASE_ALTER_INSTANT))
== ALTER_CHANGE_CREATE_OPTION) { == ALTER_OPTIONS) {
return create_option_need_rebuild(ha_alter_info, table); return create_option_need_rebuild(ha_alter_info, table);
} }
...@@ -662,8 +661,7 @@ instant_alter_column_possible( ...@@ -662,8 +661,7 @@ instant_alter_column_possible(
return false; return false;
} }
if (~ha_alter_info->handler_flags if (~ha_alter_info->handler_flags & ALTER_ADD_STORED_BASE_COLUMN) {
& ALTER_ADD_STORED_BASE_COLUMN) {
return false; return false;
} }
...@@ -686,13 +684,11 @@ instant_alter_column_possible( ...@@ -686,13 +684,11 @@ instant_alter_column_possible(
columns. */ columns. */
if (ha_alter_info->handler_flags if (ha_alter_info->handler_flags
& ((INNOBASE_ALTER_REBUILD | INNOBASE_ONLINE_CREATE) & ((INNOBASE_ALTER_REBUILD | INNOBASE_ONLINE_CREATE)
& ~ALTER_ADD_STORED_BASE_COLUMN & ~ALTER_ADD_STORED_BASE_COLUMN & ~ALTER_OPTIONS)) {
& ~ALTER_CHANGE_CREATE_OPTION)) {
return false; return false;
} }
return !(ha_alter_info->handler_flags return !(ha_alter_info->handler_flags & ALTER_OPTIONS)
& ALTER_CHANGE_CREATE_OPTION)
|| !create_option_need_rebuild(ha_alter_info, table); || !create_option_need_rebuild(ha_alter_info, table);
} }
...@@ -5457,8 +5453,7 @@ prepare_inplace_alter_table_dict( ...@@ -5457,8 +5453,7 @@ prepare_inplace_alter_table_dict(
} }
} }
if (ha_alter_info->handler_flags if (ha_alter_info->handler_flags & ALTER_OPTIONS) {
& ALTER_CHANGE_CREATE_OPTION) {
const ha_table_option_struct& alt_opt= const ha_table_option_struct& alt_opt=
*ha_alter_info->create_info->option_struct; *ha_alter_info->create_info->option_struct;
const ha_table_option_struct& opt= const ha_table_option_struct& opt=
...@@ -6827,7 +6822,7 @@ ha_innobase::prepare_inplace_alter_table( ...@@ -6827,7 +6822,7 @@ ha_innobase::prepare_inplace_alter_table(
if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA) if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA)
|| ((ha_alter_info->handler_flags & ~(INNOBASE_INPLACE_IGNORE || ((ha_alter_info->handler_flags & ~(INNOBASE_INPLACE_IGNORE
| INNOBASE_ALTER_INSTANT)) | INNOBASE_ALTER_INSTANT))
== ALTER_CHANGE_CREATE_OPTION == ALTER_OPTIONS
&& !create_option_need_rebuild(ha_alter_info, table))) { && !create_option_need_rebuild(ha_alter_info, table))) {
if (heap) { if (heap) {
...@@ -7107,8 +7102,9 @@ ha_innobase::inplace_alter_table( ...@@ -7107,8 +7102,9 @@ ha_innobase::inplace_alter_table(
DBUG_RETURN(false); DBUG_RETURN(false);
} }
if ((ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) if ((ha_alter_info->handler_flags & ~(INNOBASE_INPLACE_IGNORE
== ALTER_CHANGE_CREATE_OPTION | INNOBASE_ALTER_INSTANT))
== ALTER_OPTIONS
&& !create_option_need_rebuild(ha_alter_info, table)) { && !create_option_need_rebuild(ha_alter_info, table)) {
goto ok_exit; goto ok_exit;
} }
......
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