summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2020-05-04 13:42:38 +0530
committerThirunarayanan Balathandayuthapani <thiru@mariadb.com>2020-05-04 14:33:45 +0530
commit2748c4993c68aa4b03049a97f3657de42dd01c52 (patch)
treed0f0d5566a40626cc296a4200ccbad665233dce3
parentd233fd14a39f9c583b85ffb03e42b5ea52e2f4c2 (diff)
downloadmariadb-git-bb-10.1-MDEV-19092.tar.gz
MDEV-19092 Server crash when renaming the column whenbb-10.1-MDEV-19092
FOREIGN_KEY_CHECKS is disabled - Referenced index can be null While renaming the referenced column name. In that case, rename the referenced column name in dict_foreign_t and find the equivalent referenced index.
-rw-r--r--mysql-test/suite/innodb/r/foreign_key.result10
-rw-r--r--mysql-test/suite/innodb/t/foreign_key.test13
-rw-r--r--storage/innobase/dict/dict0mem.cc46
-rw-r--r--storage/xtradb/dict/dict0mem.cc46
4 files changed, 101 insertions, 14 deletions
diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result
index df89766e94b..7098faca0c9 100644
--- a/mysql-test/suite/innodb/r/foreign_key.result
+++ b/mysql-test/suite/innodb/r/foreign_key.result
@@ -119,4 +119,14 @@ ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES tx(x);
ALTER TABLE t1 DROP KEY idx;
ALTER TABLE t1 CHANGE a c INT;
DROP TABLE t1;
+CREATE TABLE t1 (f1 INT, f2 INT, f3 INT, KEY idx(f1)) ENGINE=InnoDB;
+ALTER TABLE t1 ADD FOREIGN KEY (f2) REFERENCES t1 (f1);
+ALTER TABLE t1 ADD COLUMN f INT;
+SET FOREIGN_KEY_CHECKS= OFF;
+ALTER TABLE t1 DROP KEY idx;
+ALTER TABLE t1 ADD KEY idx (f1);
+SET FOREIGN_KEY_CHECKS= ON;
+ALTER TABLE t1 DROP f3;
+ALTER TABLE t1 CHANGE f f3 INT;
+DROP TABLE t1;
SET FOREIGN_KEY_CHECKS=1;
diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test
index ef49a79e7ed..afaeaa073a2 100644
--- a/mysql-test/suite/innodb/t/foreign_key.test
+++ b/mysql-test/suite/innodb/t/foreign_key.test
@@ -144,4 +144,17 @@ ALTER TABLE t1 DROP KEY idx;
ALTER TABLE t1 CHANGE a c INT;
# Cleanup
DROP TABLE t1;
+
+CREATE TABLE t1 (f1 INT, f2 INT, f3 INT, KEY idx(f1)) ENGINE=InnoDB;
+ALTER TABLE t1 ADD FOREIGN KEY (f2) REFERENCES t1 (f1);
+ALTER TABLE t1 ADD COLUMN f INT;
+SET FOREIGN_KEY_CHECKS= OFF;
+ALTER TABLE t1 DROP KEY idx;
+ALTER TABLE t1 ADD KEY idx (f1);
+SET FOREIGN_KEY_CHECKS= ON;
+ALTER TABLE t1 DROP f3;
+ALTER TABLE t1 CHANGE f f3 INT;
+# Cleanup
+DROP TABLE t1;
+
SET FOREIGN_KEY_CHECKS=1;
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index bc955fb13b9..6ace0ee9a75 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -415,17 +415,15 @@ dict_mem_table_col_rename_low(
}
}
- dict_index_t* new_index = dict_foreign_find_index(
+ /* New index can be null if InnoDB already dropped
+ the foreign index when FOREIGN_KEY_CHECKS is
+ disabled */
+ foreign->foreign_index = dict_foreign_find_index(
foreign->foreign_table, NULL,
foreign->foreign_col_names,
foreign->n_fields, NULL, true, false,
NULL, NULL, NULL);
- /* New index can be null if InnoDB already dropped
- the foreign index when FOREIGN_KEY_CHECKS is
- disabled */
- foreign->foreign_index = new_index;
-
} else {
for (unsigned f = 0; f < foreign->n_fields; f++) {
@@ -447,7 +445,41 @@ dict_mem_table_col_rename_low(
foreign = *it;
- ut_ad(foreign->referenced_index != NULL);
+ if (!foreign->referenced_index) {
+ /* Referenced index could have been dropped
+ when foreign_key_checks is disabled. In that case,
+ rename the corresponding referenced_col_names and
+ find the equivalent referenced index also */
+ for (unsigned f = 0; f < foreign->n_fields; f++) {
+
+ const char*& rc =
+ foreign->referenced_col_names[f];
+ if (strcmp(rc, from)) {
+ continue;
+ }
+
+ if (to_len <= strlen(rc)) {
+ memcpy(const_cast<char*>(rc), to,
+ to_len + 1);
+ } else {
+ rc = static_cast<char*>(
+ mem_heap_dup(
+ foreign->heap,
+ to, to_len + 1));
+ }
+ }
+
+ /* New index can be null if InnoDB already dropped
+ the referenced index when FOREIGN_KEY_CHECKS is
+ disabled */
+ foreign->referenced_index = dict_foreign_find_index(
+ foreign->referenced_table, NULL,
+ foreign->referenced_col_names,
+ foreign->n_fields, NULL, true, false,
+ NULL, NULL, NULL);
+ return;
+ }
+
for (unsigned f = 0; f < foreign->n_fields; f++) {
/* foreign->referenced_col_names[] need to be
diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc
index 51ca6de8cd2..89b9bd9aead 100644
--- a/storage/xtradb/dict/dict0mem.cc
+++ b/storage/xtradb/dict/dict0mem.cc
@@ -416,17 +416,15 @@ dict_mem_table_col_rename_low(
}
}
- dict_index_t* new_index = dict_foreign_find_index(
+ /* New index can be null if XtraDB already dropped
+ the foreign index when FOREIGN_KEY_CHECKS is
+ disabled */
+ foreign->foreign_index = dict_foreign_find_index(
foreign->foreign_table, NULL,
foreign->foreign_col_names,
foreign->n_fields, NULL, true, false,
NULL, NULL, NULL);
- /* New index can be null if XtraDB already dropped
- the foreign index when FOREIGN_KEY_CHECKS is
- disabled */
- foreign->foreign_index = new_index;
-
} else {
for (unsigned f = 0; f < foreign->n_fields; f++) {
@@ -448,7 +446,41 @@ dict_mem_table_col_rename_low(
foreign = *it;
- ut_ad(foreign->referenced_index != NULL);
+ if (!foreign->referenced_index) {
+ /* Referenced index could have been dropped
+ when foreign_key_checks is disabled. In that case,
+ rename the corresponding referenced_col_names and
+ find the equivalent referenced index also */
+ for (unsigned f = 0; f < foreign->n_fields; f++) {
+
+ const char*& rc =
+ foreign->referenced_col_names[f];
+
+ if (strcmp(rc, from)) {
+ continue;
+ }
+
+ if (to_len <= strlen(rc)) {
+ memcpy(const_cast<char*>(rc), to,
+ to_len + 1);
+ } else {
+ rc = static_cast<char*>(
+ mem_heap_dup(
+ foreign->heap,
+ to, to_len + 1));
+ }
+ }
+
+ /* New index can be null if InnoDB already dropped
+ the referenced index when FOREIGN_KEY_CHECKS is
+ disabled */
+ foreign->referenced_index = dict_foreign_find_index(
+ foreign->referenced_table, NULL,
+ foreign->referenced_col_names,
+ foreign->n_fields, NULL, true, false,
+ NULL, NULL, NULL);
+ return;
+ }
for (unsigned f = 0; f < foreign->n_fields; f++) {
/* foreign->referenced_col_names[] need to be