mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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
This commit is contained in:
@ -1319,10 +1319,6 @@ partition p2008 values less than (2009)
|
||||
);
|
||||
select length(table_name) from mysql.innodb_table_stats;
|
||||
length(table_name)
|
||||
79
|
||||
79
|
||||
79
|
||||
79
|
||||
drop table extralongname_extralongname_extralongname_extralongname_ext;
|
||||
# End of 10.0 tests
|
||||
set sql_mode=default;
|
||||
|
@ -33,11 +33,19 @@ b bigint unsigned NOT NULL,
|
||||
d1 date NOT NULL,
|
||||
PRIMARY KEY (b,d1)
|
||||
) 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")
|
||||
show warnings;
|
||||
Level Code Message
|
||||
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`
|
||||
set foreign_key_checks = 0;
|
||||
DROP TABLE IF EXISTS d;
|
||||
Warnings:
|
||||
Note 1051 Unknown table 'bug_fk.d'
|
||||
|
@ -2531,9 +2531,19 @@ disconnect b;
|
||||
set foreign_key_checks=0;
|
||||
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;
|
||||
ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed")
|
||||
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;
|
||||
create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
|
||||
drop table t1;
|
||||
set foreign_key_checks=0;
|
||||
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;
|
||||
|
@ -34,13 +34,15 @@ ROLLBACK;
|
||||
InnoDB 0 transactions not purged
|
||||
INSERT INTO t2 VALUES
|
||||
(16,1551,'Omnium enim rerum'),(128,1571,' principia parva sunt');
|
||||
BEGIN;
|
||||
UPDATE t1 SET c2=c2+1;
|
||||
connect ddl, localhost, root;
|
||||
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';
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
UPDATE t1 SET c2=c2+1;
|
||||
COMMIT;
|
||||
# Kill the server
|
||||
disconnect ddl;
|
||||
# restart
|
||||
@ -61,6 +63,8 @@ DELETE FROM t2;
|
||||
ROLLBACK;
|
||||
InnoDB 0 transactions not purged
|
||||
INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum');
|
||||
BEGIN;
|
||||
DELETE FROM t1;
|
||||
connect ddl, localhost, root;
|
||||
ALTER TABLE t2 DROP COLUMN c3;
|
||||
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');
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
DELETE FROM t1;
|
||||
COMMIT;
|
||||
# Kill the server
|
||||
disconnect ddl;
|
||||
# restart
|
||||
@ -138,6 +142,8 @@ InnoDB 0 transactions not purged
|
||||
#
|
||||
# MDEV-24323 Crash on recovery after kill during instant ADD COLUMN
|
||||
#
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(0,0);
|
||||
connect ddl, localhost, root;
|
||||
CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2))
|
||||
ENGINE=InnoDB;
|
||||
@ -147,7 +153,7 @@ ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi';
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
INSERT INTO t1 VALUES(0,0);
|
||||
COMMIT;
|
||||
# Kill the server
|
||||
disconnect ddl;
|
||||
# restart
|
||||
@ -183,13 +189,15 @@ DROP TABLE t2,t3;
|
||||
#
|
||||
CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
|
||||
BEGIN;
|
||||
DELETE FROM t1;
|
||||
connect ddl, localhost, root;
|
||||
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;
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
DELETE FROM t1;
|
||||
COMMIT;
|
||||
# Kill the server
|
||||
disconnect ddl;
|
||||
# restart
|
||||
|
@ -80,9 +80,19 @@ SET FOREIGN_KEY_CHECKS=0;
|
||||
ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (a), ALGORITHM=COPY;
|
||||
INSERT INTO t1 VALUES (1,1);
|
||||
LOCK TABLES t1 WRITE;
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
TRUNCATE t1;
|
||||
ERROR HY000: Cannot add foreign key constraint for `t1`
|
||||
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;
|
||||
pk a
|
||||
1 1
|
||||
|
@ -46,7 +46,15 @@ show create table c;
|
||||
#
|
||||
# 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 (
|
||||
b bigint unsigned NOT NULL,
|
||||
d1 date NOT NULL,
|
||||
@ -54,6 +62,7 @@ CREATE TABLE b (
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
show warnings;
|
||||
set foreign_key_checks = 0;
|
||||
|
||||
DROP TABLE IF EXISTS d;
|
||||
|
||||
|
@ -1598,12 +1598,22 @@ disconnect b;
|
||||
|
||||
set foreign_key_checks=0;
|
||||
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
|
||||
--replace_result $MYSQLTEST_VARDIR . master-data/ ''
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
|
||||
set foreign_key_checks=1;
|
||||
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
|
||||
# when f_k_c is 0
|
||||
|
@ -47,6 +47,9 @@ ROLLBACK;
|
||||
INSERT INTO t2 VALUES
|
||||
(16,1551,'Omnium enim rerum'),(128,1571,' principia parva sunt');
|
||||
|
||||
BEGIN;
|
||||
UPDATE t1 SET c2=c2+1;
|
||||
|
||||
connect ddl, localhost, root;
|
||||
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
|
||||
--send
|
||||
@ -55,7 +58,7 @@ ALTER TABLE t2 DROP COLUMN c3, ADD COLUMN c5 TEXT DEFAULT 'naturam abhorrere';
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
UPDATE t1 SET c2=c2+1;
|
||||
COMMIT;
|
||||
|
||||
--source include/kill_mysqld.inc
|
||||
disconnect ddl;
|
||||
@ -73,6 +76,8 @@ ROLLBACK;
|
||||
--source include/wait_all_purged.inc
|
||||
|
||||
INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum');
|
||||
BEGIN;
|
||||
DELETE FROM t1;
|
||||
|
||||
connect ddl, localhost, root;
|
||||
ALTER TABLE t2 DROP COLUMN c3;
|
||||
@ -83,7 +88,7 @@ ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum');
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
DELETE FROM t1;
|
||||
COMMIT;
|
||||
|
||||
--source include/kill_mysqld.inc
|
||||
disconnect ddl;
|
||||
@ -177,6 +182,9 @@ DELETE FROM t2;
|
||||
--echo #
|
||||
--echo # MDEV-24323 Crash on recovery after kill during instant ADD COLUMN
|
||||
--echo #
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(0,0);
|
||||
|
||||
connect ddl, localhost, root;
|
||||
CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2))
|
||||
ENGINE=InnoDB;
|
||||
@ -189,7 +197,7 @@ ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi';
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
INSERT INTO t1 VALUES(0,0);
|
||||
COMMIT;
|
||||
|
||||
--source include/kill_mysqld.inc
|
||||
disconnect ddl;
|
||||
@ -207,6 +215,9 @@ DROP TABLE t2,t3;
|
||||
CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
|
||||
|
||||
BEGIN;
|
||||
DELETE FROM t1;
|
||||
|
||||
connect ddl, localhost, root;
|
||||
SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever';
|
||||
--send
|
||||
@ -215,7 +226,7 @@ ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST;
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR ddl';
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
DELETE FROM t1;
|
||||
COMMIT;
|
||||
|
||||
--source include/kill_mysqld.inc
|
||||
disconnect ddl;
|
||||
|
@ -92,8 +92,19 @@ SET FOREIGN_KEY_CHECKS=0;
|
||||
ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (a), ALGORITHM=COPY;
|
||||
INSERT INTO t1 VALUES (1,1);
|
||||
LOCK TABLES t1 WRITE;
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
--error ER_CANNOT_ADD_FOREIGN
|
||||
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);
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
@ -62,7 +62,6 @@ SET @saved_debug_dbug= @@debug_dbug;
|
||||
CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB;
|
||||
SET debug_dbug='+d,ib_create_table_fail_too_many_trx';
|
||||
TRUNCATE t1;
|
||||
ERROR HY000: Got error -1 "Internal error < 0 (Not system error)" from storage engine InnoDB
|
||||
SET debug_dbug=@saved_debug_dbug;
|
||||
DROP TABLE t1;
|
||||
# End of 10.3 tests
|
||||
|
@ -91,7 +91,6 @@ SET @saved_debug_dbug= @@debug_dbug;
|
||||
|
||||
CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB;
|
||||
SET debug_dbug='+d,ib_create_table_fail_too_many_trx';
|
||||
--error ER_GET_ERRNO
|
||||
TRUNCATE t1;
|
||||
SET debug_dbug=@saved_debug_dbug;
|
||||
DROP TABLE t1;
|
||||
|
@ -685,8 +685,7 @@ dict_acquire_mdl_shared(dict_table_t *table,
|
||||
}
|
||||
else
|
||||
{
|
||||
ut_ad(dict_sys.frozen());
|
||||
ut_ad(!dict_sys.locked());
|
||||
ut_ad(dict_sys.frozen_not_locked());
|
||||
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))
|
||||
latch_ex_wait_start.store(0, std::memory_order_relaxed);
|
||||
ut_ad(!latch_readers);
|
||||
ut_ad(!latch_ex);
|
||||
ut_d(latch_ex= true);
|
||||
ut_d(latch_ex= pthread_self());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -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));
|
||||
ut_ad(!latch_readers);
|
||||
ut_ad(!latch_ex);
|
||||
ut_d(latch_ex= true);
|
||||
ut_d(latch_ex= pthread_self());
|
||||
}
|
||||
|
||||
#ifdef UNIV_PFS_RWLOCK
|
||||
ATTRIBUTE_NOINLINE void dict_sys_t::unlock()
|
||||
{
|
||||
ut_ad(latch_ex);
|
||||
ut_ad(latch_ex == pthread_self());
|
||||
ut_ad(!latch_readers);
|
||||
ut_d(latch_ex= false);
|
||||
ut_d(latch_ex= 0);
|
||||
latch.wr_unlock();
|
||||
}
|
||||
|
||||
@ -2749,17 +2748,6 @@ dict_index_build_internal_fts(
|
||||
}
|
||||
/*====================== 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. */
|
||||
void
|
||||
|
@ -11473,6 +11473,8 @@ innobase_fts_load_stopword(
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
THD* thd) /*!< in: current thread */
|
||||
{
|
||||
ut_ad(dict_sys.locked());
|
||||
|
||||
const char *stopword_table= THDVAR(thd, ft_user_stopword_table);
|
||||
if (!stopword_table)
|
||||
{
|
||||
@ -11482,9 +11484,11 @@ innobase_fts_load_stopword(
|
||||
mysql_mutex_unlock(&LOCK_global_system_variables);
|
||||
}
|
||||
|
||||
return !high_level_read_only &&
|
||||
fts_load_stopword(table, trx, stopword_table,
|
||||
table->fts->dict_locked= true;
|
||||
bool success= fts_load_stopword(table, trx, stopword_table,
|
||||
THDVAR(thd, ft_enable_stopword), false);
|
||||
table->fts->dict_locked= false;
|
||||
return success;
|
||||
}
|
||||
|
||||
/** Parse the table name into normal name and remote path if needed.
|
||||
@ -12820,15 +12824,18 @@ int create_table_info_t::create_table(bool create_fk)
|
||||
dberr_t err = create_fk ? create_foreign_keys() : DB_SUCCESS;
|
||||
|
||||
if (err == DB_SUCCESS) {
|
||||
const dict_err_ignore_t ignore_err = m_trx->check_foreigns
|
||||
? DICT_ERR_IGNORE_NONE : DICT_ERR_IGNORE_FK_NOKEY;
|
||||
|
||||
/* Check that also referencing constraints are ok */
|
||||
dict_names_t fk_tables;
|
||||
err = dict_load_foreigns(m_table_name, nullptr,
|
||||
m_trx->id, true,
|
||||
DICT_ERR_IGNORE_NONE, fk_tables);
|
||||
ignore_err, fk_tables);
|
||||
while (err == DB_SUCCESS && !fk_tables.empty()) {
|
||||
dict_sys.load_table(
|
||||
{fk_tables.front(), strlen(fk_tables.front())},
|
||||
DICT_ERR_IGNORE_NONE);
|
||||
ignore_err);
|
||||
fk_tables.pop_front();
|
||||
}
|
||||
}
|
||||
@ -13109,96 +13116,59 @@ bool create_table_info_t::row_size_is_acceptable(
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Update a new table in an InnoDB database.
|
||||
@return error number */
|
||||
int
|
||||
create_table_info_t::create_table_update_dict()
|
||||
void create_table_info_t::create_table_update_dict(dict_table_t *table,
|
||||
THD *thd,
|
||||
const HA_CREATE_INFO &info,
|
||||
const TABLE &t)
|
||||
{
|
||||
dict_table_t* innobase_table;
|
||||
ut_ad(dict_sys.locked());
|
||||
|
||||
DBUG_ENTER("create_table_update_dict");
|
||||
|
||||
innobase_table = dict_table_open_on_name(
|
||||
m_table_name, false, DICT_ERR_IGNORE_NONE);
|
||||
|
||||
DBUG_ASSERT(innobase_table != 0);
|
||||
if (innobase_table->fts != NULL) {
|
||||
if (innobase_table->fts_doc_id_index == NULL) {
|
||||
innobase_table->fts_doc_id_index
|
||||
= dict_table_get_index_on_name(
|
||||
innobase_table, FTS_DOC_ID_INDEX_NAME);
|
||||
DBUG_ASSERT(innobase_table->fts_doc_id_index != NULL);
|
||||
} else {
|
||||
DBUG_ASSERT(innobase_table->fts_doc_id_index
|
||||
== dict_table_get_index_on_name(
|
||||
innobase_table,
|
||||
FTS_DOC_ID_INDEX_NAME));
|
||||
}
|
||||
DBUG_ASSERT(table->get_ref_count());
|
||||
if (table->fts)
|
||||
{
|
||||
if (!table->fts_doc_id_index)
|
||||
table->fts_doc_id_index=
|
||||
dict_table_get_index_on_name(table, FTS_DOC_ID_INDEX_NAME);
|
||||
else
|
||||
DBUG_ASSERT(table->fts_doc_id_index ==
|
||||
dict_table_get_index_on_name(table, FTS_DOC_ID_INDEX_NAME));
|
||||
}
|
||||
|
||||
DBUG_ASSERT((innobase_table->fts == NULL)
|
||||
== (innobase_table->fts_doc_id_index == NULL));
|
||||
DBUG_ASSERT(!table->fts == !table->fts_doc_id_index);
|
||||
|
||||
innobase_copy_frm_flags_from_create_info(innobase_table, m_create_info);
|
||||
|
||||
dict_stats_update(innobase_table, DICT_STATS_EMPTY_TABLE);
|
||||
innobase_copy_frm_flags_from_create_info(table, &info);
|
||||
|
||||
/* Load server stopword into FTS cache */
|
||||
if (m_flags2 & DICT_TF2_FTS) {
|
||||
if (!innobase_fts_load_stopword(innobase_table, NULL, m_thd)) {
|
||||
innobase_table->release();
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (table->flags2 & DICT_TF2_FTS &&
|
||||
innobase_fts_load_stopword(table, nullptr, thd))
|
||||
fts_optimize_add_table(table);
|
||||
|
||||
dict_sys.lock(SRW_LOCK_CALL);
|
||||
fts_optimize_add_table(innobase_table);
|
||||
dict_sys.unlock();
|
||||
}
|
||||
|
||||
if (const Field* ai = m_form->found_next_number_field) {
|
||||
if (const Field *ai = t.found_next_number_field)
|
||||
{
|
||||
ut_ad(ai->stored_in_db());
|
||||
ib_uint64_t autoinc= info.auto_increment_value;
|
||||
if (autoinc == 0)
|
||||
autoinc= 1;
|
||||
|
||||
ib_uint64_t autoinc = m_create_info->auto_increment_value;
|
||||
table->autoinc_mutex.wr_lock();
|
||||
dict_table_autoinc_initialize(table, autoinc);
|
||||
|
||||
if (autoinc == 0) {
|
||||
autoinc = 1;
|
||||
}
|
||||
|
||||
innobase_table->autoinc_mutex.wr_lock();
|
||||
dict_table_autoinc_initialize(innobase_table, autoinc);
|
||||
|
||||
if (innobase_table->is_temporary()) {
|
||||
/* AUTO_INCREMENT is not persistent for
|
||||
TEMPORARY TABLE. Temporary tables are never
|
||||
evicted. Keep the counter in memory only. */
|
||||
} else {
|
||||
const unsigned col_no = innodb_col_no(ai);
|
||||
|
||||
innobase_table->persistent_autoinc
|
||||
= static_cast<uint16_t>(
|
||||
dict_table_get_nth_col_pos(
|
||||
innobase_table, col_no, NULL)
|
||||
+ 1)
|
||||
& dict_index_t::MAX_N_FIELDS;
|
||||
|
||||
/* Persist the "last used" value, which
|
||||
typically is AUTO_INCREMENT - 1.
|
||||
if (!table->is_temporary())
|
||||
{
|
||||
const unsigned col_no= innodb_col_no(ai);
|
||||
table->persistent_autoinc= static_cast<uint16_t>
|
||||
(dict_table_get_nth_col_pos(table, col_no, nullptr) + 1) &
|
||||
dict_index_t::MAX_N_FIELDS;
|
||||
/* Persist the "last used" value, which typically is AUTO_INCREMENT - 1.
|
||||
In btr_create(), the value 0 was already written. */
|
||||
if (--autoinc) {
|
||||
btr_write_autoinc(
|
||||
dict_table_get_first_index(
|
||||
innobase_table),
|
||||
autoinc);
|
||||
}
|
||||
if (--autoinc)
|
||||
btr_write_autoinc(dict_table_get_first_index(table), autoinc);
|
||||
}
|
||||
|
||||
innobase_table->autoinc_mutex.wr_unlock();
|
||||
table->autoinc_mutex.wr_unlock();
|
||||
}
|
||||
|
||||
innobase_parse_hint_from_comment(m_thd, innobase_table, m_form->s);
|
||||
|
||||
dict_table_close(innobase_table);
|
||||
DBUG_RETURN(0);
|
||||
innobase_parse_hint_from_comment(thd, table, t.s);
|
||||
}
|
||||
|
||||
/** Allocate a new trx. */
|
||||
@ -13215,87 +13185,78 @@ create_table_info_t::allocate_trx()
|
||||
@param[in] create_info Create info (including create statement string).
|
||||
@param[in] file_per_table whether to create .ibd file
|
||||
@param[in,out] trx dictionary transaction, or NULL to create new
|
||||
@return 0 if success else error number. */
|
||||
inline int
|
||||
ha_innobase::create(
|
||||
const char* name,
|
||||
TABLE* form,
|
||||
HA_CREATE_INFO* create_info,
|
||||
bool file_per_table,
|
||||
trx_t* trx)
|
||||
@return error code
|
||||
@retval 0 on success */
|
||||
int
|
||||
ha_innobase::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info,
|
||||
bool file_per_table, trx_t *trx= nullptr)
|
||||
{
|
||||
char norm_name[FN_REFLEN]; /* {database}/{tablename} */
|
||||
char remote_path[FN_REFLEN]; /* Absolute path of table */
|
||||
|
||||
DBUG_ENTER("ha_innobase::create");
|
||||
|
||||
DBUG_ASSERT(form->s == table_share);
|
||||
DBUG_ASSERT(table_share->table_type == TABLE_TYPE_SEQUENCE
|
||||
|| table_share->table_type == TABLE_TYPE_NORMAL);
|
||||
DBUG_ASSERT(table_share->table_type == TABLE_TYPE_SEQUENCE ||
|
||||
table_share->table_type == TABLE_TYPE_NORMAL);
|
||||
|
||||
create_table_info_t info(ha_thd(),
|
||||
form,
|
||||
create_info,
|
||||
norm_name,
|
||||
remote_path,
|
||||
file_per_table, trx);
|
||||
create_table_info_t info(ha_thd(), form, create_info, norm_name,
|
||||
remote_path, file_per_table, trx);
|
||||
|
||||
{
|
||||
int error = info.initialize();
|
||||
if (!error) {
|
||||
error = info.prepare_create_table(name, !trx);
|
||||
}
|
||||
if (error) {
|
||||
if (trx) {
|
||||
trx_rollback_for_mysql(trx);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
int error= info.initialize();
|
||||
if (!error)
|
||||
error= info.prepare_create_table(name, !trx);
|
||||
if (error)
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
}
|
||||
|
||||
const bool own_trx = !trx;
|
||||
int error = 0;
|
||||
|
||||
if (own_trx) {
|
||||
const bool own_trx= !trx;
|
||||
if (own_trx)
|
||||
{
|
||||
info.allocate_trx();
|
||||
trx = info.trx();
|
||||
trx= info.trx();
|
||||
DBUG_ASSERT(trx_state_eq(trx, TRX_STATE_NOT_STARTED));
|
||||
}
|
||||
if (own_trx && !(info.flags2() & DICT_TF2_TEMPORARY)) {
|
||||
|
||||
if (!(info.flags2() & DICT_TF2_TEMPORARY))
|
||||
{
|
||||
trx_start_for_ddl(trx);
|
||||
if (dberr_t err = lock_sys_tables(trx)) {
|
||||
error = convert_error_code_to_mysql(err, 0, nullptr);
|
||||
if (dberr_t err= lock_sys_tables(trx))
|
||||
error= convert_error_code_to_mysql(err, 0, nullptr);
|
||||
}
|
||||
}
|
||||
if (own_trx) {
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
error = info.create_table(own_trx);
|
||||
}
|
||||
if (!error)
|
||||
error= info.create_table(own_trx);
|
||||
|
||||
if (error) {
|
||||
/* Rollback will drop the being-created table. */
|
||||
if (own_trx || (info.flags2() & DICT_TF2_TEMPORARY))
|
||||
{
|
||||
if (error)
|
||||
trx_rollback_for_mysql(trx);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
} else {
|
||||
/* When this is invoked as part of ha_innobase::truncate(),
|
||||
the old copy of the table will be deleted here. */
|
||||
else
|
||||
{
|
||||
std::vector<pfs_os_file_t> deleted;
|
||||
trx->commit(deleted);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
for (pfs_os_file_t d : deleted) os_file_close(d);
|
||||
error = info.create_table_update_dict();
|
||||
if (!(info.flags2() & DICT_TF2_TEMPORARY)) {
|
||||
log_write_up_to(trx->commit_lsn, true);
|
||||
}
|
||||
ut_ad(deleted.empty());
|
||||
info.table()->acquire();
|
||||
info.create_table_update_dict(info.table(), info.thd(),
|
||||
*create_info, *form);
|
||||
}
|
||||
|
||||
if (own_trx) {
|
||||
if (own_trx)
|
||||
{
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
dict_stats_update(info.table(), DICT_STATS_EMPTY_TABLE);
|
||||
if (!info.table()->is_temporary())
|
||||
log_write_up_to(trx->commit_lsn, true);
|
||||
info.table()->release();
|
||||
}
|
||||
trx->free();
|
||||
}
|
||||
}
|
||||
else if (!error && m_prebuilt)
|
||||
m_prebuilt->table= info.table();
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
@ -13305,11 +13266,8 @@ ha_innobase::create(
|
||||
@param[in] form Table format; columns and index information.
|
||||
@param[in] create_info Create info (including create statement string).
|
||||
@return 0 if success else error number. */
|
||||
int
|
||||
ha_innobase::create(
|
||||
const char* name,
|
||||
TABLE* form,
|
||||
HA_CREATE_INFO* create_info)
|
||||
int ha_innobase::create(const char *name, TABLE *form,
|
||||
HA_CREATE_INFO *create_info)
|
||||
{
|
||||
return create(name, form, create_info, srv_file_per_table);
|
||||
}
|
||||
@ -13844,210 +13802,230 @@ int ha_innobase::truncate()
|
||||
|
||||
update_thd();
|
||||
|
||||
if (is_read_only()) {
|
||||
if (is_read_only())
|
||||
DBUG_RETURN(HA_ERR_TABLE_READONLY);
|
||||
}
|
||||
|
||||
HA_CREATE_INFO info;
|
||||
dict_table_t* ib_table = m_prebuilt->table;
|
||||
dict_table_t *ib_table= m_prebuilt->table;
|
||||
info.init();
|
||||
update_create_info_from_table(&info, table);
|
||||
switch (dict_tf_get_rec_format(ib_table->flags)) {
|
||||
case REC_FORMAT_REDUNDANT:
|
||||
info.row_type = ROW_TYPE_REDUNDANT;
|
||||
info.row_type= ROW_TYPE_REDUNDANT;
|
||||
break;
|
||||
case REC_FORMAT_COMPACT:
|
||||
info.row_type = ROW_TYPE_COMPACT;
|
||||
info.row_type= ROW_TYPE_COMPACT;
|
||||
break;
|
||||
case REC_FORMAT_COMPRESSED:
|
||||
info.row_type = ROW_TYPE_COMPRESSED;
|
||||
info.row_type= ROW_TYPE_COMPRESSED;
|
||||
break;
|
||||
case REC_FORMAT_DYNAMIC:
|
||||
info.row_type = ROW_TYPE_DYNAMIC;
|
||||
info.row_type= ROW_TYPE_DYNAMIC;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto stored_lock = m_prebuilt->stored_select_lock_type;
|
||||
trx_t* trx = innobase_trx_allocate(m_user_thd);
|
||||
const auto stored_lock= m_prebuilt->stored_select_lock_type;
|
||||
trx_t *trx= innobase_trx_allocate(m_user_thd);
|
||||
trx_start_for_ddl(trx);
|
||||
|
||||
if (ib_table->is_temporary()) {
|
||||
if (ib_table->is_temporary())
|
||||
{
|
||||
info.options|= HA_LEX_CREATE_TMP_TABLE;
|
||||
btr_drop_temporary_table(*ib_table);
|
||||
m_prebuilt->table = nullptr;
|
||||
m_prebuilt->table= nullptr;
|
||||
row_prebuilt_free(m_prebuilt);
|
||||
m_prebuilt = nullptr;
|
||||
m_prebuilt= nullptr;
|
||||
my_free(m_upd_buf);
|
||||
m_upd_buf = nullptr;
|
||||
m_upd_buf_size = 0;
|
||||
m_upd_buf= nullptr;
|
||||
m_upd_buf_size= 0;
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
ib_table->release();
|
||||
dict_sys.remove(ib_table, false, true);
|
||||
int err= create(ib_table->name.m_name, table, &info, true, trx);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
int err = create(ib_table->name.m_name, table, &info, true,
|
||||
trx);
|
||||
ut_ad(!err);
|
||||
if (!err) {
|
||||
err = open(ib_table->name.m_name, 0, 0);
|
||||
m_prebuilt->stored_select_lock_type = stored_lock;
|
||||
if (!err)
|
||||
{
|
||||
err= open(ib_table->name.m_name, 0, 0);
|
||||
m_prebuilt->table->release();
|
||||
m_prebuilt->stored_select_lock_type= stored_lock;
|
||||
}
|
||||
|
||||
trx->free();
|
||||
|
||||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
if (UT_LIST_GET_LEN(ib_table->freed_indexes)) {
|
||||
ib_table->vc_templ = nullptr;
|
||||
ib_table->id = 0;
|
||||
DBUG_RETURN(err);
|
||||
if (UT_LIST_GET_LEN(ib_table->freed_indexes))
|
||||
{
|
||||
ib_table->vc_templ= nullptr;
|
||||
ib_table->id= 0;
|
||||
}
|
||||
else
|
||||
#endif /* BTR_CUR_HASH_ADAPT */
|
||||
|
||||
dict_mem_table_free(ib_table);
|
||||
|
||||
DBUG_RETURN(err);
|
||||
}
|
||||
|
||||
mem_heap_t* heap = mem_heap_create(1000);
|
||||
mem_heap_t *heap= mem_heap_create(1000);
|
||||
|
||||
dict_get_and_save_data_dir_path(ib_table);
|
||||
info.data_file_name = ib_table->data_dir_path;
|
||||
const char* temp_name = dict_mem_create_temporary_tablename(
|
||||
heap, ib_table->name.m_name, ib_table->id);
|
||||
const char* name = mem_heap_strdup(heap, ib_table->name.m_name);
|
||||
info.data_file_name= ib_table->data_dir_path;
|
||||
const char *temp_name=
|
||||
dict_mem_create_temporary_tablename(heap,
|
||||
ib_table->name.m_name, ib_table->id);
|
||||
const char *name= mem_heap_strdup(heap, ib_table->name.m_name);
|
||||
|
||||
dict_table_t *table_stats = nullptr, *index_stats = nullptr;
|
||||
MDL_ticket *mdl_table = nullptr, *mdl_index = nullptr;
|
||||
|
||||
dberr_t error = DB_SUCCESS;
|
||||
dberr_t error= DB_SUCCESS;
|
||||
|
||||
dict_sys.freeze(SRW_LOCK_CALL);
|
||||
for (const dict_foreign_t* f : ib_table->referenced_set) {
|
||||
if (dict_table_t* child = f->foreign_table) {
|
||||
error = lock_table_for_trx(child, trx, LOCK_X);
|
||||
if (error != DB_SUCCESS) {
|
||||
for (const dict_foreign_t *f : ib_table->referenced_set)
|
||||
if (dict_table_t *child= f->foreign_table)
|
||||
if ((error= lock_table_for_trx(child, trx, LOCK_X)) != DB_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dict_sys.unfreeze();
|
||||
|
||||
if (error == DB_SUCCESS) {
|
||||
error = lock_table_for_trx(ib_table, trx, LOCK_X);
|
||||
}
|
||||
if (error == DB_SUCCESS)
|
||||
error= lock_table_for_trx(ib_table, trx, LOCK_X);
|
||||
|
||||
const bool fts = error == DB_SUCCESS
|
||||
&& ib_table->flags2 & (DICT_TF2_FTS_HAS_DOC_ID | DICT_TF2_FTS);
|
||||
const bool fts= error == DB_SUCCESS &&
|
||||
ib_table->flags2 & (DICT_TF2_FTS_HAS_DOC_ID | DICT_TF2_FTS);
|
||||
|
||||
if (fts) {
|
||||
if (fts)
|
||||
{
|
||||
fts_optimize_remove_table(ib_table);
|
||||
purge_sys.stop_FTS(*ib_table);
|
||||
error = fts_lock_tables(trx, *ib_table);
|
||||
error= fts_lock_tables(trx, *ib_table);
|
||||
}
|
||||
|
||||
/* Wait for purge threads to stop using the table. */
|
||||
for (uint n = 15; ib_table->get_ref_count() > 1; ) {
|
||||
if (!--n) {
|
||||
error = DB_LOCK_WAIT_TIMEOUT;
|
||||
for (uint n = 15; ib_table->get_ref_count() > 1; )
|
||||
{
|
||||
if (!--n)
|
||||
{
|
||||
error= DB_LOCK_WAIT_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
if (error == DB_SUCCESS && dict_stats_is_persistent_enabled(ib_table)
|
||||
&& !ib_table->is_stats_table()) {
|
||||
if (error == DB_SUCCESS && dict_stats_is_persistent_enabled(ib_table) &&
|
||||
!ib_table->is_stats_table())
|
||||
{
|
||||
table_stats= dict_table_open_on_name(TABLE_STATS_NAME, false,
|
||||
DICT_ERR_IGNORE_NONE);
|
||||
if (table_stats) {
|
||||
if (table_stats)
|
||||
{
|
||||
dict_sys.freeze(SRW_LOCK_CALL);
|
||||
table_stats = dict_acquire_mdl_shared<false>(
|
||||
table_stats, m_user_thd, &mdl_table);
|
||||
table_stats= dict_acquire_mdl_shared<false>(table_stats, m_user_thd,
|
||||
&mdl_table);
|
||||
dict_sys.unfreeze();
|
||||
}
|
||||
index_stats = dict_table_open_on_name(INDEX_STATS_NAME, false,
|
||||
index_stats= dict_table_open_on_name(INDEX_STATS_NAME, false,
|
||||
DICT_ERR_IGNORE_NONE);
|
||||
if (index_stats) {
|
||||
if (index_stats)
|
||||
{
|
||||
dict_sys.freeze(SRW_LOCK_CALL);
|
||||
index_stats = dict_acquire_mdl_shared<false>(
|
||||
index_stats, m_user_thd, &mdl_index);
|
||||
index_stats= dict_acquire_mdl_shared<false>(index_stats, m_user_thd,
|
||||
&mdl_index);
|
||||
dict_sys.unfreeze();
|
||||
}
|
||||
|
||||
if (table_stats && index_stats
|
||||
&& !strcmp(table_stats->name.m_name, TABLE_STATS_NAME)
|
||||
&& !strcmp(index_stats->name.m_name, INDEX_STATS_NAME) &&
|
||||
!(error = lock_table_for_trx(table_stats, trx, LOCK_X))) {
|
||||
error = lock_table_for_trx(index_stats, trx, LOCK_X);
|
||||
}
|
||||
if (table_stats && index_stats &&
|
||||
!strcmp(table_stats->name.m_name, TABLE_STATS_NAME) &&
|
||||
!strcmp(index_stats->name.m_name, INDEX_STATS_NAME) &&
|
||||
!(error= lock_table_for_trx(table_stats, trx, LOCK_X)))
|
||||
error= lock_table_for_trx(index_stats, trx, LOCK_X);
|
||||
}
|
||||
|
||||
if (error == DB_SUCCESS) {
|
||||
error = lock_sys_tables(trx);
|
||||
}
|
||||
if (error == DB_SUCCESS)
|
||||
error= lock_sys_tables(trx);
|
||||
|
||||
std::vector<pfs_os_file_t> deleted;
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
if (error == DB_SUCCESS) {
|
||||
error = innobase_rename_table(trx, ib_table->name.m_name,
|
||||
temp_name, false);
|
||||
|
||||
if (error == DB_SUCCESS) {
|
||||
error = trx->drop_table(*ib_table);
|
||||
}
|
||||
if (error == DB_SUCCESS)
|
||||
{
|
||||
error= innobase_rename_table(trx, ib_table->name.m_name, temp_name, false);
|
||||
if (error == DB_SUCCESS)
|
||||
error= trx->drop_table(*ib_table);
|
||||
}
|
||||
|
||||
int err = convert_error_code_to_mysql(error, ib_table->flags,
|
||||
m_user_thd);
|
||||
if (err) {
|
||||
trx_rollback_for_mysql(trx);
|
||||
if (fts) {
|
||||
fts_optimize_add_table(ib_table);
|
||||
purge_sys.resume_FTS();
|
||||
}
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
} else {
|
||||
int err = convert_error_code_to_mysql(error, ib_table->flags, m_user_thd);
|
||||
const auto update_time = ib_table->update_time;
|
||||
const auto stored_lock = m_prebuilt->stored_select_lock_type;
|
||||
const auto def_trx_id = ib_table->def_trx_id;
|
||||
ib_table->release();
|
||||
m_prebuilt->table = nullptr;
|
||||
|
||||
err = create(name, table, &info,
|
||||
dict_table_is_file_per_table(ib_table), trx);
|
||||
/* On success, create() durably committed trx. */
|
||||
if (fts) {
|
||||
purge_sys.resume_FTS();
|
||||
if (err)
|
||||
{
|
||||
trx_rollback_for_mysql(trx);
|
||||
if (fts)
|
||||
fts_optimize_add_table(ib_table);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto def_trx_id= ib_table->def_trx_id;
|
||||
ib_table->release();
|
||||
m_prebuilt->table= nullptr;
|
||||
|
||||
err= create(name, table, &info, dict_table_is_file_per_table(ib_table),
|
||||
trx);
|
||||
if (!err)
|
||||
{
|
||||
m_prebuilt->table->acquire();
|
||||
create_table_info_t::create_table_update_dict(m_prebuilt->table,
|
||||
m_user_thd, info, *table);
|
||||
trx->commit(deleted);
|
||||
}
|
||||
else
|
||||
{
|
||||
trx_rollback_for_mysql(trx);
|
||||
m_prebuilt->table= dict_table_open_on_name(name, true,
|
||||
DICT_ERR_IGNORE_FK_NOKEY);
|
||||
m_prebuilt->table->def_trx_id= def_trx_id;
|
||||
}
|
||||
dict_names_t fk_tables;
|
||||
dict_load_foreigns(m_prebuilt->table->name.m_name, nullptr, 1, true,
|
||||
DICT_ERR_IGNORE_FK_NOKEY, fk_tables);
|
||||
for (const char *f : fk_tables)
|
||||
dict_sys.load_table({f, strlen(f)});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
reload:
|
||||
m_prebuilt->table = dict_table_open_on_name(
|
||||
name, false, DICT_ERR_IGNORE_NONE);
|
||||
m_prebuilt->table->def_trx_id = def_trx_id;
|
||||
} else {
|
||||
row_prebuilt_t* prebuilt = m_prebuilt;
|
||||
uchar* upd_buf = m_upd_buf;
|
||||
ulint upd_buf_size = m_upd_buf_size;
|
||||
if (fts)
|
||||
purge_sys.resume_FTS();
|
||||
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
for (pfs_os_file_t d : deleted) os_file_close(d);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
dict_stats_update(m_prebuilt->table, DICT_STATS_EMPTY_TABLE);
|
||||
log_write_up_to(trx->commit_lsn, true);
|
||||
row_prebuilt_t *prebuilt= m_prebuilt;
|
||||
uchar *upd_buf= m_upd_buf;
|
||||
ulint upd_buf_size= m_upd_buf_size;
|
||||
/* Mimic ha_innobase::close(). */
|
||||
m_prebuilt = nullptr;
|
||||
m_upd_buf = nullptr;
|
||||
m_upd_buf_size = 0;
|
||||
m_prebuilt= nullptr;
|
||||
m_upd_buf= nullptr;
|
||||
m_upd_buf_size= 0;
|
||||
|
||||
err = open(name, 0, 0);
|
||||
|
||||
if (!err) {
|
||||
m_prebuilt->stored_select_lock_type
|
||||
= stored_lock;
|
||||
m_prebuilt->table->update_time = update_time;
|
||||
err= open(name, 0, 0);
|
||||
if (!err)
|
||||
{
|
||||
m_prebuilt->stored_select_lock_type= stored_lock;
|
||||
m_prebuilt->table->update_time= update_time;
|
||||
row_prebuilt_free(prebuilt);
|
||||
my_free(upd_buf);
|
||||
} else {
|
||||
/* Revert to the old table. */
|
||||
m_prebuilt = prebuilt;
|
||||
m_upd_buf = upd_buf;
|
||||
m_upd_buf_size = upd_buf_size;
|
||||
goto reload;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Revert to the old table. */
|
||||
m_prebuilt= prebuilt;
|
||||
m_upd_buf= upd_buf;
|
||||
m_upd_buf_size= upd_buf_size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -14055,12 +14033,10 @@ reload:
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
if (table_stats) {
|
||||
if (table_stats)
|
||||
dict_table_close(table_stats, false, m_user_thd, mdl_table);
|
||||
}
|
||||
if (index_stats) {
|
||||
if (index_stats)
|
||||
dict_table_close(index_stats, false, m_user_thd, mdl_index);
|
||||
}
|
||||
|
||||
DBUG_RETURN(err);
|
||||
}
|
||||
@ -15656,30 +15632,12 @@ delete is then allowed internally to resolve a duplicate key conflict in
|
||||
REPLACE, not an update.
|
||||
@return > 0 if referenced by a FOREIGN KEY */
|
||||
|
||||
uint
|
||||
ha_innobase::referenced_by_foreign_key(void)
|
||||
/*========================================*/
|
||||
uint ha_innobase::referenced_by_foreign_key()
|
||||
{
|
||||
if (dict_table_is_referenced_by_foreign_key(m_prebuilt->table)) {
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Frees the foreign key create info for a table stored in InnoDB, if it is
|
||||
non-NULL. */
|
||||
|
||||
void
|
||||
ha_innobase::free_foreign_key_create_info(
|
||||
/*======================================*/
|
||||
char* str) /*!< in, own: create info string to free */
|
||||
{
|
||||
if (str != NULL) {
|
||||
my_free(str);
|
||||
}
|
||||
dict_sys.freeze(SRW_LOCK_CALL);
|
||||
const bool empty= m_prebuilt->table->referenced_set.empty();
|
||||
dict_sys.unfreeze();
|
||||
return !empty;
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
|
@ -190,12 +190,12 @@ public:
|
||||
|
||||
void update_create_info(HA_CREATE_INFO* create_info) override;
|
||||
|
||||
inline int create(
|
||||
int create(
|
||||
const char* name,
|
||||
TABLE* form,
|
||||
HA_CREATE_INFO* create_info,
|
||||
bool file_per_table,
|
||||
trx_t* trx = NULL);
|
||||
trx_t* trx);
|
||||
|
||||
int create(
|
||||
const char* name,
|
||||
@ -225,7 +225,7 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
@ -639,8 +639,9 @@ public:
|
||||
@param create_fk whether to add FOREIGN KEY constraints */
|
||||
int create_table(bool create_fk = true);
|
||||
|
||||
/** Update the internal data dictionary. */
|
||||
int create_table_update_dict();
|
||||
static void create_table_update_dict(dict_table_t* table, THD* thd,
|
||||
const HA_CREATE_INFO& info,
|
||||
const TABLE& t);
|
||||
|
||||
/** Validates the create options. Checks that the options
|
||||
KEY_BLOCK_SIZE, ROW_FORMAT, DATA DIRECTORY, TEMPORARY & TABLESPACE
|
||||
@ -700,12 +701,13 @@ public:
|
||||
trx_t* trx() const
|
||||
{ return(m_trx); }
|
||||
|
||||
/** Return table name. */
|
||||
const char* table_name() const
|
||||
{ return(m_table_name); }
|
||||
/** @return table name */
|
||||
const char* table_name() const { return(m_table_name); }
|
||||
|
||||
THD* thd() const
|
||||
{ return(m_thd); }
|
||||
/** @return the created table */
|
||||
dict_table_t *table() const { return m_table; }
|
||||
|
||||
THD* thd() const { return(m_thd); }
|
||||
|
||||
private:
|
||||
/** Parses the table name into normal name and either temp path or
|
||||
|
@ -7286,13 +7286,10 @@ error_handling_drop_uncached:
|
||||
goto error_handling;
|
||||
}
|
||||
|
||||
ctx->new_table->fts->dict_locked = true;
|
||||
|
||||
error = innobase_fts_load_stopword(
|
||||
ctx->new_table, ctx->trx,
|
||||
ctx->prebuilt->trx->mysql_thd)
|
||||
? DB_SUCCESS : DB_ERROR;
|
||||
ctx->new_table->fts->dict_locked = false;
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
goto error_handling;
|
||||
@ -9882,7 +9879,7 @@ innobase_update_foreign_cache(
|
||||
|
||||
err = dict_load_foreigns(user_table->name.m_name,
|
||||
ctx->col_names, 1, true,
|
||||
DICT_ERR_IGNORE_NONE,
|
||||
DICT_ERR_IGNORE_FK_NOKEY,
|
||||
fk_tables);
|
||||
|
||||
if (err == DB_CANNOT_ADD_CONSTRAINT) {
|
||||
|
@ -421,14 +421,6 @@ dict_foreign_add_to_cache(
|
||||
dict_err_ignore_t ignore_err)
|
||||
/*!< in: error to be ignored */
|
||||
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
|
||||
foreign key lists of the table.
|
||||
@ -1329,7 +1321,7 @@ class dict_sys_t
|
||||
alignas(CPU_LEVEL1_DCACHE_LINESIZE) srw_lock latch;
|
||||
#ifdef UNIV_DEBUG
|
||||
/** 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 */
|
||||
Atomic_counter<uint32_t> latch_readers;
|
||||
#endif
|
||||
@ -1503,11 +1495,12 @@ public:
|
||||
/** @return whether any thread (not necessarily the current thread)
|
||||
is holding the latch; that is, this check may return false
|
||||
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)
|
||||
is holding the exclusive latch; that is, this check may return false
|
||||
positives */
|
||||
bool locked() const { return latch_ex; }
|
||||
is holding a shared latch */
|
||||
bool frozen_not_locked() const { return latch_readers; }
|
||||
/** @return whether the current thread holds the exclusive latch */
|
||||
bool locked() const { return latch_ex == pthread_self(); }
|
||||
#endif
|
||||
private:
|
||||
/** Acquire the exclusive latch */
|
||||
@ -1526,7 +1519,7 @@ public:
|
||||
{
|
||||
ut_ad(!latch_readers);
|
||||
ut_ad(!latch_ex);
|
||||
ut_d(latch_ex= true);
|
||||
ut_d(latch_ex= pthread_self());
|
||||
}
|
||||
else
|
||||
lock_wait(SRW_LOCK_ARGS(file, line));
|
||||
@ -1543,9 +1536,9 @@ public:
|
||||
/** Unlock the data dictionary cache. */
|
||||
void unlock()
|
||||
{
|
||||
ut_ad(latch_ex);
|
||||
ut_ad(latch_ex == pthread_self());
|
||||
ut_ad(!latch_readers);
|
||||
ut_d(latch_ex= false);
|
||||
ut_d(latch_ex= 0);
|
||||
latch.wr_unlock();
|
||||
}
|
||||
/** Acquire a shared lock on the dictionary cache. */
|
||||
|
@ -100,7 +100,7 @@ dict_load_foreigns(
|
||||
which must be loaded
|
||||
subsequently to load all the
|
||||
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.
|
||||
|
@ -3934,8 +3934,7 @@ void lock_release(trx_t *trx)
|
||||
#ifdef UNIV_DEBUG
|
||||
std::set<table_id_t> to_evict;
|
||||
if (innodb_evict_tables_on_commit_debug &&
|
||||
!trx->is_recovered && !trx->dict_operation &&
|
||||
!trx->dict_operation_lock_mode)
|
||||
!trx->is_recovered && !dict_sys.locked())
|
||||
for (const auto& p : trx->mod_tables)
|
||||
if (!p.first->is_temporary())
|
||||
to_evict.emplace(p.first->id);
|
||||
|
Reference in New Issue
Block a user