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

MDEV-29504/MDEV-29849 TRUNCATE breaks FOREIGN KEY locking

ha_innobase::referenced_by_foreign_key(): Protect the check with
dict_sys.freeze(), to prevent races with TRUNCATE TABLE.
The test innodb.instant_alter_crash has been adjusted for this
additional locking.

dict_table_is_referenced_by_foreign_key(): Removed (merged to
the only caller).

create_table_info_t::create_table(): Ignore missing indexes for
FOREIGN KEY constraints if foreign_key_checks=0.

create_table_info_t::create_table_update_dict(): Rewritten as
a static function. Do not return any error.

ha_innobase::create(): When trx!=nullptr and we are operating
on a persistent table, do not rollback, commit, or release the
data dictionary latch.

ha_innobase::truncate(): Protect the entire critical section
with an exclusive dict_sys.latch, so that
ha_innobase::referenced_by_foreign_key() on referenced tables
will return a consistent result. In case of a failure,
invoke dict_load_foreigns() to restore also any FOREIGN KEY
constraints.

ha_innobase::free_foreign_key_create_info(): Define inline.

lock_release(): Disregard innodb_evict_tables_on_commit_debug=ON
when dict_sys.locked() holds. It would hold when fts_load_stopword()
is invoked by create_table_info_t::create_table_update_dict().

dict_sys_t::locked(): Return whether the current thread is holding
the exclusive dict_sys.latch.

dict_sys_t::frozen_not_locked(): Return whether any thread is
holding a shared dict_sys.latch.

In the test main.mysql_upgrade, the InnoDB persistent statistics
will no longer be recalculated in ha_innobase::open() as part of
CHECK TABLE ... FOR UPGRADE. They were deleted earlier in the test.

Tested by: Matthias Leich
parent f4519fb7
...@@ -1319,10 +1319,6 @@ partition p2008 values less than (2009) ...@@ -1319,10 +1319,6 @@ partition p2008 values less than (2009)
); );
select length(table_name) from mysql.innodb_table_stats; select length(table_name) from mysql.innodb_table_stats;
length(table_name) length(table_name)
79
79
79
79
drop table extralongname_extralongname_extralongname_extralongname_ext; drop table extralongname_extralongname_extralongname_extralongname_ext;
# End of 10.0 tests # End of 10.0 tests
set sql_mode=default; set sql_mode=default;
......
...@@ -33,11 +33,19 @@ b bigint unsigned NOT NULL, ...@@ -33,11 +33,19 @@ b bigint unsigned NOT NULL,
d1 date NOT NULL, d1 date NOT NULL,
PRIMARY KEY (b,d1) PRIMARY KEY (b,d1)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
DROP TABLE b;
set foreign_key_checks = 1;
CREATE TABLE b (
b bigint unsigned NOT NULL,
d1 date NOT NULL,
PRIMARY KEY (b,d1)
) ENGINE=InnoDB;
ERROR HY000: Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed") ERROR HY000: Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed")
show warnings; show warnings;
Level Code Message Level Code Message
Error 1005 Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed") Error 1005 Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint for `b` Warning 1215 Cannot add foreign key constraint for `b`
set foreign_key_checks = 0;
DROP TABLE IF EXISTS d; DROP TABLE IF EXISTS d;
Warnings: Warnings:
Note 1051 Unknown table 'bug_fk.d' Note 1051 Unknown table 'bug_fk.d'
......
...@@ -2531,9 +2531,19 @@ disconnect b; ...@@ -2531,9 +2531,19 @@ disconnect b;
set foreign_key_checks=0; set foreign_key_checks=0;
create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb;
create table t1(a char(10) primary key, b varchar(20)) engine = innodb; create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed")
set foreign_key_checks=1; set foreign_key_checks=1;
insert into t2 values (1,1);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`a`))
set foreign_key_checks=0;
drop table t1;
set foreign_key_checks=1;
insert into t2 values (1,1);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`a`))
create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed")
drop table t2; drop table t2;
create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
drop table t1;
set foreign_key_checks=0; set foreign_key_checks=0;
create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1;
create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8;
......
...@@ -34,13 +34,15 @@ ROLLBACK; ...@@ -34,13 +34,15 @@ ROLLBACK;
InnoDB 0 transactions not purged InnoDB 0 transactions not purged
INSERT INTO t2 VALUES INSERT INTO t2 VALUES
(16,1551,'Omnium enim rerum'),(128,1571,' principia parva sunt'); (16,1551,'Omnium enim rerum'),(128,1571,' principia parva sunt');
BEGIN;
UPDATE t1 SET c2=c2+1;
connect ddl, localhost, root; connect ddl, localhost, root;
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
ALTER TABLE t2 DROP COLUMN c3, ADD COLUMN c5 TEXT DEFAULT 'naturam abhorrere'; ALTER TABLE t2 DROP COLUMN c3, ADD COLUMN c5 TEXT DEFAULT 'naturam abhorrere';
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR ddl'; SET DEBUG_SYNC='now WAIT_FOR ddl';
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
UPDATE t1 SET c2=c2+1; COMMIT;
# Kill the server # Kill the server
disconnect ddl; disconnect ddl;
# restart # restart
...@@ -61,6 +63,8 @@ DELETE FROM t2; ...@@ -61,6 +63,8 @@ DELETE FROM t2;
ROLLBACK; ROLLBACK;
InnoDB 0 transactions not purged InnoDB 0 transactions not purged
INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum'); INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum');
BEGIN;
DELETE FROM t1;
connect ddl, localhost, root; connect ddl, localhost, root;
ALTER TABLE t2 DROP COLUMN c3; ALTER TABLE t2 DROP COLUMN c3;
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
...@@ -68,7 +72,7 @@ ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum'); ...@@ -68,7 +72,7 @@ ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum');
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR ddl'; SET DEBUG_SYNC='now WAIT_FOR ddl';
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
DELETE FROM t1; COMMIT;
# Kill the server # Kill the server
disconnect ddl; disconnect ddl;
# restart # restart
...@@ -138,6 +142,8 @@ InnoDB 0 transactions not purged ...@@ -138,6 +142,8 @@ InnoDB 0 transactions not purged
# #
# MDEV-24323 Crash on recovery after kill during instant ADD COLUMN # MDEV-24323 Crash on recovery after kill during instant ADD COLUMN
# #
BEGIN;
INSERT INTO t1 VALUES(0,0);
connect ddl, localhost, root; connect ddl, localhost, root;
CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2)) CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2))
ENGINE=InnoDB; ENGINE=InnoDB;
...@@ -147,7 +153,7 @@ ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi'; ...@@ -147,7 +153,7 @@ ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi';
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR ddl'; SET DEBUG_SYNC='now WAIT_FOR ddl';
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
INSERT INTO t1 VALUES(0,0); COMMIT;
# Kill the server # Kill the server
disconnect ddl; disconnect ddl;
# restart # restart
...@@ -183,13 +189,15 @@ DROP TABLE t2,t3; ...@@ -183,13 +189,15 @@ DROP TABLE t2,t3;
# #
CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6); INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
BEGIN;
DELETE FROM t1;
connect ddl, localhost, root; connect ddl, localhost, root;
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST; ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST;
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR ddl'; SET DEBUG_SYNC='now WAIT_FOR ddl';
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
DELETE FROM t1; COMMIT;
# Kill the server # Kill the server
disconnect ddl; disconnect ddl;
# restart # restart
......
...@@ -80,9 +80,19 @@ SET FOREIGN_KEY_CHECKS=0; ...@@ -80,9 +80,19 @@ SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (a), ALGORITHM=COPY; ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (a), ALGORITHM=COPY;
INSERT INTO t1 VALUES (1,1); INSERT INTO t1 VALUES (1,1);
LOCK TABLES t1 WRITE; LOCK TABLES t1 WRITE;
SET FOREIGN_KEY_CHECKS=1;
TRUNCATE t1; TRUNCATE t1;
ERROR HY000: Cannot add foreign key constraint for `t1` ERROR HY000: Cannot add foreign key constraint for `t1`
INSERT INTO t1 VALUES (2,2); INSERT INTO t1 VALUES (2,2);
ERROR HY000: Table 't1' was not locked with LOCK TABLES
SELECT * FROM t1;
pk a
1 1
UNLOCK TABLES;
INSERT INTO t1 VALUES (2,2);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
SET FOREIGN_KEY_CHECKS=0;
INSERT INTO t1 VALUES (2,2);
SELECT * FROM t1; SELECT * FROM t1;
pk a pk a
1 1 1 1
......
...@@ -46,7 +46,15 @@ show create table c; ...@@ -46,7 +46,15 @@ show create table c;
# #
# Note that column b has different type in parent table # Note that column b has different type in parent table
# #
--error 1005 CREATE TABLE b (
b bigint unsigned NOT NULL,
d1 date NOT NULL,
PRIMARY KEY (b,d1)
) ENGINE=InnoDB;
DROP TABLE b;
set foreign_key_checks = 1;
--error ER_CANT_CREATE_TABLE
CREATE TABLE b ( CREATE TABLE b (
b bigint unsigned NOT NULL, b bigint unsigned NOT NULL,
d1 date NOT NULL, d1 date NOT NULL,
...@@ -54,6 +62,7 @@ CREATE TABLE b ( ...@@ -54,6 +62,7 @@ CREATE TABLE b (
) ENGINE=InnoDB; ) ENGINE=InnoDB;
show warnings; show warnings;
set foreign_key_checks = 0;
DROP TABLE IF EXISTS d; DROP TABLE IF EXISTS d;
...@@ -64,7 +73,7 @@ CREATE TABLE d ( ...@@ -64,7 +73,7 @@ CREATE TABLE d (
CONSTRAINT bd_fk FOREIGN KEY (b) REFERENCES b (b) CONSTRAINT bd_fk FOREIGN KEY (b) REFERENCES b (b)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
show warnings; show warnings;
set foreign_key_checks = 1; set foreign_key_checks = 1;
......
...@@ -1598,12 +1598,22 @@ disconnect b; ...@@ -1598,12 +1598,22 @@ disconnect b;
set foreign_key_checks=0; set foreign_key_checks=0;
create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb;
create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
set foreign_key_checks=1;
--error ER_NO_REFERENCED_ROW_2
insert into t2 values (1,1);
set foreign_key_checks=0;
drop table t1;
set foreign_key_checks=1;
--error ER_NO_REFERENCED_ROW_2
insert into t2 values (1,1);
# Embedded server doesn't chdir to data directory # Embedded server doesn't chdir to data directory
--replace_result $MYSQLTEST_VARDIR . master-data/ '' --replace_result $MYSQLTEST_VARDIR . master-data/ ''
--error ER_CANT_CREATE_TABLE --error ER_CANT_CREATE_TABLE
create table t1(a char(10) primary key, b varchar(20)) engine = innodb; create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
set foreign_key_checks=1;
drop table t2; drop table t2;
create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
drop table t1;
# test that FKs between different charsets are not accepted in CREATE even # test that FKs between different charsets are not accepted in CREATE even
# when f_k_c is 0 # when f_k_c is 0
......
...@@ -47,6 +47,9 @@ ROLLBACK; ...@@ -47,6 +47,9 @@ ROLLBACK;
INSERT INTO t2 VALUES INSERT INTO t2 VALUES
(16,1551,'Omnium enim rerum'),(128,1571,' principia parva sunt'); (16,1551,'Omnium enim rerum'),(128,1571,' principia parva sunt');
BEGIN;
UPDATE t1 SET c2=c2+1;
connect ddl, localhost, root; connect ddl, localhost, root;
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
--send --send
...@@ -55,7 +58,7 @@ ALTER TABLE t2 DROP COLUMN c3, ADD COLUMN c5 TEXT DEFAULT 'naturam abhorrere'; ...@@ -55,7 +58,7 @@ ALTER TABLE t2 DROP COLUMN c3, ADD COLUMN c5 TEXT DEFAULT 'naturam abhorrere';
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR ddl'; SET DEBUG_SYNC='now WAIT_FOR ddl';
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
UPDATE t1 SET c2=c2+1; COMMIT;
--source include/kill_mysqld.inc --source include/kill_mysqld.inc
disconnect ddl; disconnect ddl;
...@@ -73,6 +76,8 @@ ROLLBACK; ...@@ -73,6 +76,8 @@ ROLLBACK;
--source include/wait_all_purged.inc --source include/wait_all_purged.inc
INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum'); INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum');
BEGIN;
DELETE FROM t1;
connect ddl, localhost, root; connect ddl, localhost, root;
ALTER TABLE t2 DROP COLUMN c3; ALTER TABLE t2 DROP COLUMN c3;
...@@ -83,7 +88,7 @@ ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum'); ...@@ -83,7 +88,7 @@ ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum');
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR ddl'; SET DEBUG_SYNC='now WAIT_FOR ddl';
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
DELETE FROM t1; COMMIT;
--source include/kill_mysqld.inc --source include/kill_mysqld.inc
disconnect ddl; disconnect ddl;
...@@ -177,6 +182,9 @@ DELETE FROM t2; ...@@ -177,6 +182,9 @@ DELETE FROM t2;
--echo # --echo #
--echo # MDEV-24323 Crash on recovery after kill during instant ADD COLUMN --echo # MDEV-24323 Crash on recovery after kill during instant ADD COLUMN
--echo # --echo #
BEGIN;
INSERT INTO t1 VALUES(0,0);
connect ddl, localhost, root; connect ddl, localhost, root;
CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2)) CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2))
ENGINE=InnoDB; ENGINE=InnoDB;
...@@ -189,7 +197,7 @@ ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi'; ...@@ -189,7 +197,7 @@ ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi';
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR ddl'; SET DEBUG_SYNC='now WAIT_FOR ddl';
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
INSERT INTO t1 VALUES(0,0); COMMIT;
--source include/kill_mysqld.inc --source include/kill_mysqld.inc
disconnect ddl; disconnect ddl;
...@@ -207,6 +215,9 @@ DROP TABLE t2,t3; ...@@ -207,6 +215,9 @@ DROP TABLE t2,t3;
CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6); INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
BEGIN;
DELETE FROM t1;
connect ddl, localhost, root; connect ddl, localhost, root;
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
--send --send
...@@ -215,7 +226,7 @@ ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST; ...@@ -215,7 +226,7 @@ ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST;
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR ddl'; SET DEBUG_SYNC='now WAIT_FOR ddl';
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
DELETE FROM t1; COMMIT;
--source include/kill_mysqld.inc --source include/kill_mysqld.inc
disconnect ddl; disconnect ddl;
......
...@@ -92,8 +92,19 @@ SET FOREIGN_KEY_CHECKS=0; ...@@ -92,8 +92,19 @@ SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (a), ALGORITHM=COPY; ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (a), ALGORITHM=COPY;
INSERT INTO t1 VALUES (1,1); INSERT INTO t1 VALUES (1,1);
LOCK TABLES t1 WRITE; LOCK TABLES t1 WRITE;
SET FOREIGN_KEY_CHECKS=1;
--error ER_CANNOT_ADD_FOREIGN --error ER_CANNOT_ADD_FOREIGN
TRUNCATE t1; TRUNCATE t1;
# Whether TRUNCATE succeeds or fails, it will reload FOREIGN KEY constraints.
# As a result, ha_innobase::referenced_by_foreign_key() will retun TRUE
# (for the self-referential key), and the statement will fail.
--error ER_TABLE_NOT_LOCKED
INSERT INTO t1 VALUES (2,2);
SELECT * FROM t1;
UNLOCK TABLES;
--error ER_NO_REFERENCED_ROW_2
INSERT INTO t1 VALUES (2,2);
SET FOREIGN_KEY_CHECKS=0;
INSERT INTO t1 VALUES (2,2); INSERT INTO t1 VALUES (2,2);
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
......
...@@ -62,7 +62,6 @@ SET @saved_debug_dbug= @@debug_dbug; ...@@ -62,7 +62,6 @@ SET @saved_debug_dbug= @@debug_dbug;
CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB; CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB;
SET debug_dbug='+d,ib_create_table_fail_too_many_trx'; SET debug_dbug='+d,ib_create_table_fail_too_many_trx';
TRUNCATE t1; TRUNCATE t1;
ERROR HY000: Got error -1 "Internal error < 0 (Not system error)" from storage engine InnoDB
SET debug_dbug=@saved_debug_dbug; SET debug_dbug=@saved_debug_dbug;
DROP TABLE t1; DROP TABLE t1;
# End of 10.3 tests # End of 10.3 tests
......
...@@ -91,7 +91,6 @@ SET @saved_debug_dbug= @@debug_dbug; ...@@ -91,7 +91,6 @@ SET @saved_debug_dbug= @@debug_dbug;
CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB; CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB;
SET debug_dbug='+d,ib_create_table_fail_too_many_trx'; SET debug_dbug='+d,ib_create_table_fail_too_many_trx';
--error ER_GET_ERRNO
TRUNCATE t1; TRUNCATE t1;
SET debug_dbug=@saved_debug_dbug; SET debug_dbug=@saved_debug_dbug;
DROP TABLE t1; DROP TABLE t1;
......
...@@ -685,8 +685,7 @@ dict_acquire_mdl_shared(dict_table_t *table, ...@@ -685,8 +685,7 @@ dict_acquire_mdl_shared(dict_table_t *table,
} }
else else
{ {
ut_ad(dict_sys.frozen()); ut_ad(dict_sys.frozen_not_locked());
ut_ad(!dict_sys.locked());
db_len= dict_get_db_name_len(table->name.m_name); db_len= dict_get_db_name_len(table->name.m_name);
} }
...@@ -1003,7 +1002,7 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line)) ...@@ -1003,7 +1002,7 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line))
latch_ex_wait_start.store(0, std::memory_order_relaxed); latch_ex_wait_start.store(0, std::memory_order_relaxed);
ut_ad(!latch_readers); ut_ad(!latch_readers);
ut_ad(!latch_ex); ut_ad(!latch_ex);
ut_d(latch_ex= true); ut_d(latch_ex= pthread_self());
return; return;
} }
...@@ -1021,15 +1020,15 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line)) ...@@ -1021,15 +1020,15 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line))
latch.wr_lock(SRW_LOCK_ARGS(file, line)); latch.wr_lock(SRW_LOCK_ARGS(file, line));
ut_ad(!latch_readers); ut_ad(!latch_readers);
ut_ad(!latch_ex); ut_ad(!latch_ex);
ut_d(latch_ex= true); ut_d(latch_ex= pthread_self());
} }
#ifdef UNIV_PFS_RWLOCK #ifdef UNIV_PFS_RWLOCK
ATTRIBUTE_NOINLINE void dict_sys_t::unlock() ATTRIBUTE_NOINLINE void dict_sys_t::unlock()
{ {
ut_ad(latch_ex); ut_ad(latch_ex == pthread_self());
ut_ad(!latch_readers); ut_ad(!latch_readers);
ut_d(latch_ex= false); ut_d(latch_ex= 0);
latch.wr_unlock(); latch.wr_unlock();
} }
...@@ -2749,17 +2748,6 @@ dict_index_build_internal_fts( ...@@ -2749,17 +2748,6 @@ dict_index_build_internal_fts(
} }
/*====================== FOREIGN KEY PROCESSING ========================*/ /*====================== FOREIGN KEY PROCESSING ========================*/
/*********************************************************************//**
Checks if a table is referenced by foreign keys.
@return TRUE if table is referenced by a foreign key */
ibool
dict_table_is_referenced_by_foreign_key(
/*====================================*/
const dict_table_t* table) /*!< in: InnoDB table */
{
return(!table->referenced_set.empty());
}
/**********************************************************************//** /**********************************************************************//**
Removes a foreign constraint struct from the dictionary cache. */ Removes a foreign constraint struct from the dictionary cache. */
void void
......
This diff is collapsed.
...@@ -190,12 +190,12 @@ class ha_innobase final : public handler ...@@ -190,12 +190,12 @@ class ha_innobase final : public handler
void update_create_info(HA_CREATE_INFO* create_info) override; void update_create_info(HA_CREATE_INFO* create_info) override;
inline int create( int create(
const char* name, const char* name,
TABLE* form, TABLE* form,
HA_CREATE_INFO* create_info, HA_CREATE_INFO* create_info,
bool file_per_table, bool file_per_table,
trx_t* trx = NULL); trx_t* trx);
int create( int create(
const char* name, const char* name,
...@@ -225,7 +225,7 @@ class ha_innobase final : public handler ...@@ -225,7 +225,7 @@ class ha_innobase final : public handler
uint referenced_by_foreign_key() override; uint referenced_by_foreign_key() override;
void free_foreign_key_create_info(char* str) override; void free_foreign_key_create_info(char* str) override { my_free(str); }
uint lock_count(void) const override; uint lock_count(void) const override;
...@@ -639,8 +639,9 @@ class create_table_info_t ...@@ -639,8 +639,9 @@ class create_table_info_t
@param create_fk whether to add FOREIGN KEY constraints */ @param create_fk whether to add FOREIGN KEY constraints */
int create_table(bool create_fk = true); int create_table(bool create_fk = true);
/** Update the internal data dictionary. */ static void create_table_update_dict(dict_table_t* table, THD* thd,
int create_table_update_dict(); const HA_CREATE_INFO& info,
const TABLE& t);
/** Validates the create options. Checks that the options /** Validates the create options. Checks that the options
KEY_BLOCK_SIZE, ROW_FORMAT, DATA DIRECTORY, TEMPORARY & TABLESPACE KEY_BLOCK_SIZE, ROW_FORMAT, DATA DIRECTORY, TEMPORARY & TABLESPACE
...@@ -700,12 +701,13 @@ class create_table_info_t ...@@ -700,12 +701,13 @@ class create_table_info_t
trx_t* trx() const trx_t* trx() const
{ return(m_trx); } { return(m_trx); }
/** Return table name. */ /** @return table name */
const char* table_name() const const char* table_name() const { return(m_table_name); }
{ return(m_table_name); }
/** @return the created table */
dict_table_t *table() const { return m_table; }
THD* thd() const THD* thd() const { return(m_thd); }
{ return(m_thd); }
private: private:
/** Parses the table name into normal name and either temp path or /** Parses the table name into normal name and either temp path or
......
...@@ -7286,13 +7286,10 @@ prepare_inplace_alter_table_dict( ...@@ -7286,13 +7286,10 @@ prepare_inplace_alter_table_dict(
goto error_handling; goto error_handling;
} }
ctx->new_table->fts->dict_locked = true;
error = innobase_fts_load_stopword( error = innobase_fts_load_stopword(
ctx->new_table, ctx->trx, ctx->new_table, ctx->trx,
ctx->prebuilt->trx->mysql_thd) ctx->prebuilt->trx->mysql_thd)
? DB_SUCCESS : DB_ERROR; ? DB_SUCCESS : DB_ERROR;
ctx->new_table->fts->dict_locked = false;
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
goto error_handling; goto error_handling;
...@@ -9882,7 +9879,7 @@ innobase_update_foreign_cache( ...@@ -9882,7 +9879,7 @@ innobase_update_foreign_cache(
err = dict_load_foreigns(user_table->name.m_name, err = dict_load_foreigns(user_table->name.m_name,
ctx->col_names, 1, true, ctx->col_names, 1, true,
DICT_ERR_IGNORE_NONE, DICT_ERR_IGNORE_FK_NOKEY,
fk_tables); fk_tables);
if (err == DB_CANNOT_ADD_CONSTRAINT) { if (err == DB_CANNOT_ADD_CONSTRAINT) {
......
...@@ -421,14 +421,6 @@ dict_foreign_add_to_cache( ...@@ -421,14 +421,6 @@ dict_foreign_add_to_cache(
dict_err_ignore_t ignore_err) dict_err_ignore_t ignore_err)
/*!< in: error to be ignored */ /*!< in: error to be ignored */
MY_ATTRIBUTE((nonnull(1), warn_unused_result)); MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/*********************************************************************//**
Checks if a table is referenced by foreign keys.
@return TRUE if table is referenced by a foreign key */
ibool
dict_table_is_referenced_by_foreign_key(
/*====================================*/
const dict_table_t* table) /*!< in: InnoDB table */
MY_ATTRIBUTE((nonnull, warn_unused_result));
/**********************************************************************//** /**********************************************************************//**
Replace the index passed in with another equivalent index in the Replace the index passed in with another equivalent index in the
foreign key lists of the table. foreign key lists of the table.
...@@ -1329,7 +1321,7 @@ class dict_sys_t ...@@ -1329,7 +1321,7 @@ class dict_sys_t
alignas(CPU_LEVEL1_DCACHE_LINESIZE) srw_lock latch; alignas(CPU_LEVEL1_DCACHE_LINESIZE) srw_lock latch;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/** whether latch is being held in exclusive mode (by any thread) */ /** whether latch is being held in exclusive mode (by any thread) */
bool latch_ex; Atomic_relaxed<pthread_t> latch_ex;
/** number of S-latch holders */ /** number of S-latch holders */
Atomic_counter<uint32_t> latch_readers; Atomic_counter<uint32_t> latch_readers;
#endif #endif
...@@ -1503,11 +1495,12 @@ class dict_sys_t ...@@ -1503,11 +1495,12 @@ class dict_sys_t
/** @return whether any thread (not necessarily the current thread) /** @return whether any thread (not necessarily the current thread)
is holding the latch; that is, this check may return false is holding the latch; that is, this check may return false
positives */ positives */
bool frozen() const { return latch_readers || locked(); } bool frozen() const { return latch_readers || latch_ex; }
/** @return whether any thread (not necessarily the current thread) /** @return whether any thread (not necessarily the current thread)
is holding the exclusive latch; that is, this check may return false is holding a shared latch */
positives */ bool frozen_not_locked() const { return latch_readers; }
bool locked() const { return latch_ex; } /** @return whether the current thread holds the exclusive latch */
bool locked() const { return latch_ex == pthread_self(); }
#endif #endif
private: private:
/** Acquire the exclusive latch */ /** Acquire the exclusive latch */
...@@ -1526,7 +1519,7 @@ class dict_sys_t ...@@ -1526,7 +1519,7 @@ class dict_sys_t
{ {
ut_ad(!latch_readers); ut_ad(!latch_readers);
ut_ad(!latch_ex); ut_ad(!latch_ex);
ut_d(latch_ex= true); ut_d(latch_ex= pthread_self());
} }
else else
lock_wait(SRW_LOCK_ARGS(file, line)); lock_wait(SRW_LOCK_ARGS(file, line));
...@@ -1543,9 +1536,9 @@ class dict_sys_t ...@@ -1543,9 +1536,9 @@ class dict_sys_t
/** Unlock the data dictionary cache. */ /** Unlock the data dictionary cache. */
void unlock() void unlock()
{ {
ut_ad(latch_ex); ut_ad(latch_ex == pthread_self());
ut_ad(!latch_readers); ut_ad(!latch_readers);
ut_d(latch_ex= false); ut_d(latch_ex= 0);
latch.wr_unlock(); latch.wr_unlock();
} }
/** Acquire a shared lock on the dictionary cache. */ /** Acquire a shared lock on the dictionary cache. */
......
...@@ -100,7 +100,7 @@ dict_load_foreigns( ...@@ -100,7 +100,7 @@ dict_load_foreigns(
which must be loaded which must be loaded
subsequently to load all the subsequently to load all the
foreign key constraints. */ foreign key constraints. */
MY_ATTRIBUTE((nonnull(1), warn_unused_result)); MY_ATTRIBUTE((nonnull(1)));
/********************************************************************//** /********************************************************************//**
This function opens a system table, and return the first record. This function opens a system table, and return the first record.
......
...@@ -3934,8 +3934,7 @@ void lock_release(trx_t *trx) ...@@ -3934,8 +3934,7 @@ void lock_release(trx_t *trx)
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
std::set<table_id_t> to_evict; std::set<table_id_t> to_evict;
if (innodb_evict_tables_on_commit_debug && if (innodb_evict_tables_on_commit_debug &&
!trx->is_recovered && !trx->dict_operation && !trx->is_recovered && !dict_sys.locked())
!trx->dict_operation_lock_mode)
for (const auto& p : trx->mod_tables) for (const auto& p : trx->mod_tables)
if (!p.first->is_temporary()) if (!p.first->is_temporary())
to_evict.emplace(p.first->id); to_evict.emplace(p.first->id);
......
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