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.
parent 7df17ca8
......@@ -128,3 +128,29 @@ HANDLER h READ `PRIMARY` PREV WHERE 0;
pk f1 f2 f3 f4 f5 f6 f7 f8 filler
HANDLER h CLOSE;
DROP TABLE t1;
CREATE TABLE t1(f1 int not null, primary key(f1))engine=innodb;
CREATE TABLE t2(f1 INT AUTO_INCREMENT NOT NULL, f2 INT NOT NULL,
status ENUM ('a', 'b', 'c'), INDEX idx1(f2),
PRIMARY KEY(f1),
FOREIGN KEY (f2) REFERENCES t1(f1))ENGINE=InnoDB;
ALTER TABLE t1 CHANGE f1 f1_id INT NOT NULL, ADD f3 VARCHAR(255) DEFAULT NULL;
ALTER TABLE t1 CHANGE f1_id f1 INT NOT NULL;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f1` int(11) NOT NULL,
`f3` varchar(255) DEFAULT NULL,
PRIMARY KEY (`f1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`f1` int(11) NOT NULL AUTO_INCREMENT,
`f2` int(11) NOT NULL,
`status` enum('a','b','c') DEFAULT NULL,
PRIMARY KEY (`f1`),
KEY `idx1` (`f2`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `t1` (`f1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
ALTER TABLE t2 CHANGE status status VARCHAR(20) DEFAULT NULL;
DROP TABLE t2, t1;
......@@ -134,5 +134,23 @@ HANDLER h READ `PRIMARY` PREV WHERE 0;
# Cleanup
HANDLER h CLOSE;
DROP TABLE t1;
# MDEV-19630 ALTER TABLE ... ADD COLUMN damages foreign keys which are pointed
# to the table being altered
CREATE TABLE t1(f1 int not null, primary key(f1))engine=innodb;
CREATE TABLE t2(f1 INT AUTO_INCREMENT NOT NULL, f2 INT NOT NULL,
status ENUM ('a', 'b', 'c'), INDEX idx1(f2),
PRIMARY KEY(f1),
FOREIGN KEY (f2) REFERENCES t1(f1))ENGINE=InnoDB;
ALTER TABLE t1 CHANGE f1 f1_id INT NOT NULL, ADD f3 VARCHAR(255) DEFAULT NULL;
ALTER TABLE t1 CHANGE f1_id f1 INT NOT NULL;
SHOW CREATE TABLE t1;
SHOW CREATE TABLE t2;
ALTER TABLE t2 CHANGE status status VARCHAR(20) DEFAULT NULL;
DROP TABLE t2, t1;
--let $datadir= `select @@datadir`
--remove_file $datadir/test/load.data
......@@ -7441,14 +7441,14 @@ innobase_drop_foreign_try(
}
/** Rename a column in the data dictionary tables.
@param[in] user_table InnoDB table that was being altered
@param[in] trx data dictionary transaction
@param[in] table_name Table name in MySQL
@param[in] nth_col 0-based index of the column
@param[in] from old column name
@param[in] to new column name
@param[in] new_clustered whether the table has been rebuilt
@param[in] is_virtual whether it is a virtual column
@param[in] user_table InnoDB table that was being altered
@param[in] trx Data dictionary transaction
@param[in] table_name Table name in MySQL
@param[in] nth_col 0-based index of the column
@param[in] from old column name
@param[in] to new column name
@param[in] new_clustered whether the table has been rebuilt
@param[in] evict_fk_cache Evict the fk info from cache
@retval true Failure
@retval false Success */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
......@@ -7460,7 +7460,8 @@ innobase_rename_column_try(
ulint nth_col,
const char* from,
const char* to,
bool new_clustered)
bool new_clustered,
bool evict_fk_cache)
{
pars_info_t* info;
dberr_t error;
......@@ -7644,7 +7645,8 @@ innobase_rename_column_try(
}
}
if (new_clustered) {
/* Reload the foreign key info for instant table too. */
if (new_clustered || evict_fk_cache) {
std::for_each(fk_evict.begin(), fk_evict.end(),
dict_foreign_remove_from_cache);
}
......@@ -7699,7 +7701,8 @@ innobase_rename_columns_try(
col_n,
cf->field->field_name.str,
cf->field_name.str,
ctx->need_rebuild())) {
ctx->need_rebuild(),
ctx->is_instant())) {
return(true);
}
goto processed_field;
......
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