Skip to content

Commit 07b1a26

Browse files
MDEV-19630 ALTER TABLE ... ADD COLUMN damages foreign keys
which are pointed to the table being altered Problem: ======== InnoDB failed to change the column name present in foreign key cache for instant add column. So it leads to column mismatch for the consecutive rename of column. Solution: ========= Evict the foreign key information from cache and load the foreign key information again for instant operation.
1 parent 7df17ca commit 07b1a26

File tree

3 files changed

+58
-11
lines changed

3 files changed

+58
-11
lines changed

mysql-test/suite/innodb/r/instant_alter_bugs.result

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,29 @@ HANDLER h READ `PRIMARY` PREV WHERE 0;
128128
pk f1 f2 f3 f4 f5 f6 f7 f8 filler
129129
HANDLER h CLOSE;
130130
DROP TABLE t1;
131+
CREATE TABLE t1(f1 int not null, primary key(f1))engine=innodb;
132+
CREATE TABLE t2(f1 INT AUTO_INCREMENT NOT NULL, f2 INT NOT NULL,
133+
status ENUM ('a', 'b', 'c'), INDEX idx1(f2),
134+
PRIMARY KEY(f1),
135+
FOREIGN KEY (f2) REFERENCES t1(f1))ENGINE=InnoDB;
136+
ALTER TABLE t1 CHANGE f1 f1_id INT NOT NULL, ADD f3 VARCHAR(255) DEFAULT NULL;
137+
ALTER TABLE t1 CHANGE f1_id f1 INT NOT NULL;
138+
SHOW CREATE TABLE t1;
139+
Table Create Table
140+
t1 CREATE TABLE `t1` (
141+
`f1` int(11) NOT NULL,
142+
`f3` varchar(255) DEFAULT NULL,
143+
PRIMARY KEY (`f1`)
144+
) ENGINE=InnoDB DEFAULT CHARSET=latin1
145+
SHOW CREATE TABLE t2;
146+
Table Create Table
147+
t2 CREATE TABLE `t2` (
148+
`f1` int(11) NOT NULL AUTO_INCREMENT,
149+
`f2` int(11) NOT NULL,
150+
`status` enum('a','b','c') DEFAULT NULL,
151+
PRIMARY KEY (`f1`),
152+
KEY `idx1` (`f2`),
153+
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `t1` (`f1`)
154+
) ENGINE=InnoDB DEFAULT CHARSET=latin1
155+
ALTER TABLE t2 CHANGE status status VARCHAR(20) DEFAULT NULL;
156+
DROP TABLE t2, t1;

mysql-test/suite/innodb/t/instant_alter_bugs.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,23 @@ HANDLER h READ `PRIMARY` PREV WHERE 0;
134134
# Cleanup
135135
HANDLER h CLOSE;
136136
DROP TABLE t1;
137+
138+
# MDEV-19630 ALTER TABLE ... ADD COLUMN damages foreign keys which are pointed
139+
# to the table being altered
140+
CREATE TABLE t1(f1 int not null, primary key(f1))engine=innodb;
141+
CREATE TABLE t2(f1 INT AUTO_INCREMENT NOT NULL, f2 INT NOT NULL,
142+
status ENUM ('a', 'b', 'c'), INDEX idx1(f2),
143+
PRIMARY KEY(f1),
144+
FOREIGN KEY (f2) REFERENCES t1(f1))ENGINE=InnoDB;
145+
146+
ALTER TABLE t1 CHANGE f1 f1_id INT NOT NULL, ADD f3 VARCHAR(255) DEFAULT NULL;
147+
ALTER TABLE t1 CHANGE f1_id f1 INT NOT NULL;
148+
149+
SHOW CREATE TABLE t1;
150+
SHOW CREATE TABLE t2;
151+
152+
ALTER TABLE t2 CHANGE status status VARCHAR(20) DEFAULT NULL;
153+
DROP TABLE t2, t1;
154+
137155
--let $datadir= `select @@datadir`
138156
--remove_file $datadir/test/load.data

storage/innobase/handler/handler0alter.cc

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7441,14 +7441,14 @@ innobase_drop_foreign_try(
74417441
}
74427442

74437443
/** Rename a column in the data dictionary tables.
7444-
@param[in] user_table InnoDB table that was being altered
7445-
@param[in] trx data dictionary transaction
7446-
@param[in] table_name Table name in MySQL
7447-
@param[in] nth_col 0-based index of the column
7448-
@param[in] from old column name
7449-
@param[in] to new column name
7450-
@param[in] new_clustered whether the table has been rebuilt
7451-
@param[in] is_virtual whether it is a virtual column
7444+
@param[in] user_table InnoDB table that was being altered
7445+
@param[in] trx Data dictionary transaction
7446+
@param[in] table_name Table name in MySQL
7447+
@param[in] nth_col 0-based index of the column
7448+
@param[in] from old column name
7449+
@param[in] to new column name
7450+
@param[in] new_clustered whether the table has been rebuilt
7451+
@param[in] evict_fk_cache Evict the fk info from cache
74527452
@retval true Failure
74537453
@retval false Success */
74547454
static MY_ATTRIBUTE((nonnull, warn_unused_result))
@@ -7460,7 +7460,8 @@ innobase_rename_column_try(
74607460
ulint nth_col,
74617461
const char* from,
74627462
const char* to,
7463-
bool new_clustered)
7463+
bool new_clustered,
7464+
bool evict_fk_cache)
74647465
{
74657466
pars_info_t* info;
74667467
dberr_t error;
@@ -7644,7 +7645,8 @@ innobase_rename_column_try(
76447645
}
76457646
}
76467647

7647-
if (new_clustered) {
7648+
/* Reload the foreign key info for instant table too. */
7649+
if (new_clustered || evict_fk_cache) {
76487650
std::for_each(fk_evict.begin(), fk_evict.end(),
76497651
dict_foreign_remove_from_cache);
76507652
}
@@ -7699,7 +7701,8 @@ innobase_rename_columns_try(
76997701
col_n,
77007702
cf->field->field_name.str,
77017703
cf->field_name.str,
7702-
ctx->need_rebuild())) {
7704+
ctx->need_rebuild(),
7705+
ctx->is_instant())) {
77037706
return(true);
77047707
}
77057708
goto processed_field;

0 commit comments

Comments
 (0)