summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2021-05-20 15:47:21 +0530
committerThirunarayanan Balathandayuthapani <thiru@mariadb.com>2021-05-23 15:53:59 +0530
commit349d77ecdd8ed549005ac000a80e3e0126fbd80a (patch)
tree5195c6caa25c22a6f02b1fc4f59869098c0d5b37
parent98f7b2cb09d73758e3f2af6d57b6e0a804387d3e (diff)
downloadmariadb-git-349d77ecdd8ed549005ac000a80e3e0126fbd80a.tar.gz
MDEV-25721 Double free of table when inplace alter
FTS add index fails Problem: ======== InnoDB double frees the table if auxiliary fts table creation fails and fails to set the dict operation for the transaction. It leads to failure while dropping newly added index. Solution: ========= InnoDB should avoid double freeing and set the dictionary operation of transaction in fts_create_common_tables()
-rw-r--r--mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result12
-rw-r--r--mysql-test/suite/innodb_fts/t/innodb-fts-ddl.opt1
-rw-r--r--mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test20
-rw-r--r--storage/innobase/fts/fts0fts.cc33
4 files changed, 55 insertions, 11 deletions
diff --git a/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result b/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result
index f1e625037f3..4efab17d441 100644
--- a/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result
+++ b/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result
@@ -266,3 +266,15 @@ t1 CREATE TABLE `t1` (
`f1` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1;
+#
+# MDEV-25271 Double free of table when inplace alter
+# FTS add index fails
+#
+call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation.");
+call mtr.add_suppression("InnoDB: Error number .* means");
+call mtr.add_suppression("InnoDB: Cannot create file");
+call mtr.add_suppression("InnoDB: Failed to create");
+CREATE TABLE t1(a TEXT, FTS_DOC_ID BIGINT UNSIGNED NOT NULL UNIQUE) ENGINE=InnoDB;
+ALTER TABLE t1 ADD FULLTEXT(a), ALGORITHM=INPLACE;
+ERROR HY000: Got error 11 "Resource temporarily unavailable" from storage engine InnoDB
+DROP TABLE t1;
diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.opt b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.opt
new file mode 100644
index 00000000000..e6ae8d0fe0a
--- /dev/null
+++ b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.opt
@@ -0,0 +1 @@
+--enable-plugin-innodb-sys-tables
diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test
index e055acc4968..824e719b7a8 100644
--- a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test
+++ b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test
@@ -319,3 +319,23 @@ ALTER TABLE t1 ADD FTS_DOC_ID INT UNSIGNED NOT NULL, ALGORITHM=INPLACE;
SHOW CREATE TABLE t1;
DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-25271 Double free of table when inplace alter
+--echo # FTS add index fails
+--echo #
+call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation.");
+call mtr.add_suppression("InnoDB: Error number .* means");
+call mtr.add_suppression("InnoDB: Cannot create file");
+call mtr.add_suppression("InnoDB: Failed to create");
+
+let MYSQLD_DATADIR=`select @@datadir`;
+CREATE TABLE t1(a TEXT, FTS_DOC_ID BIGINT UNSIGNED NOT NULL UNIQUE) ENGINE=InnoDB;
+let $fts_aux_file= `select concat('FTS_',right(concat(repeat('0',16), lower(hex(TABLE_ID))),16),'_BEING_DELETED.ibd') FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='test/t1'`;
+write_file $MYSQLD_DATADIR/test/$fts_aux_file;
+EOF
+--error ER_GET_ERRNO
+ALTER TABLE t1 ADD FULLTEXT(a), ALGORITHM=INPLACE;
+DROP TABLE t1;
+remove_file $MYSQLD_DATADIR/test/$fts_aux_file;
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index a74b5083128..53928cac5dd 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -1787,7 +1787,6 @@ fts_create_one_common_table(
error = row_create_table_for_mysql(new_table, trx,
FIL_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY);
-
if (error == DB_SUCCESS) {
dict_index_t* index = dict_mem_index_create(
@@ -1808,17 +1807,22 @@ fts_create_one_common_table(
error = row_create_index_for_mysql(index, trx, NULL);
trx->dict_operation = op;
+ } else {
+err_exit:
+ new_table = NULL;
+ ib::warn() << "Failed to create FTS common table "
+ << fts_table_name;
+ trx->error_state = error;
+ return NULL;
}
if (error != DB_SUCCESS) {
dict_mem_table_free(new_table);
- new_table = NULL;
- ib::warn() << "Failed to create FTS common table "
- << fts_table_name;
trx->error_state = DB_SUCCESS;
row_drop_table_for_mysql(fts_table_name, trx, SQLCOM_DROP_DB);
- trx->error_state = error;
+ goto err_exit;
}
+
return(new_table);
}
@@ -1866,6 +1870,8 @@ fts_create_common_tables(
FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table);
+ op = trx_get_dict_operation(trx);
+
error = fts_drop_common_tables(trx, &fts_table);
if (error != DB_SUCCESS) {
@@ -1882,6 +1888,7 @@ fts_create_common_tables(
trx, table, full_name[i], fts_table.suffix, heap);
if (common_table == NULL) {
+ trx->error_state = DB_SUCCESS;
error = DB_ERROR;
goto func_exit;
} else {
@@ -1926,8 +1933,6 @@ fts_create_common_tables(
error = row_create_index_for_mysql(index, trx, NULL);
- trx->dict_operation = op;
-
func_exit:
if (error != DB_SUCCESS) {
for (it = common_tables.begin(); it != common_tables.end();
@@ -1937,6 +1942,8 @@ func_exit:
}
}
+ trx->dict_operation = op;
+
common_tables.clear();
mem_heap_free(heap);
@@ -2019,16 +2026,20 @@ fts_create_one_index_table(
error = row_create_index_for_mysql(index, trx, NULL);
trx->dict_operation = op;
+ } else {
+err_exit:
+ new_table = NULL;
+ ib::warn() << "Failed to create FTS index table "
+ << table_name;
+ trx->error_state = error;
+ return NULL;
}
if (error != DB_SUCCESS) {
dict_mem_table_free(new_table);
- new_table = NULL;
- ib::warn() << "Failed to create FTS index table "
- << table_name;
trx->error_state = DB_SUCCESS;
row_drop_table_for_mysql(table_name, trx, SQLCOM_DROP_DB);
- trx->error_state = error;
+ goto err_exit;
}
return(new_table);