summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-07-21 17:33:16 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2020-07-21 17:33:16 +0300
commit4ec032b492de5c392f66c9c1764cbf72442ed3a9 (patch)
tree0d9d0173f285df28d525fab7fbefd6879174e4a7
parentc89366866bca2df46b0592719a1f6b6dabf470cb (diff)
parentb1538f4d60bf30de00417a7c3f948d2de654fcb3 (diff)
downloadmariadb-git-4ec032b492de5c392f66c9c1764cbf72442ed3a9.tar.gz
Merge 10.4 into 10.5
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_charset.result63
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_charset.test73
-rw-r--r--mysql-test/suite/rpl/r/parallel_backup.result40
-rw-r--r--mysql-test/suite/rpl/t/parallel_backup.test75
-rw-r--r--mysql-test/suite/sql_sequence/kill.result12
-rw-r--r--mysql-test/suite/sql_sequence/kill.test20
-rw-r--r--mysql-test/suite/versioning/r/update.result31
-rw-r--r--mysql-test/suite/versioning/t/update.test41
-rw-r--r--sql/handler.cc96
-rw-r--r--sql/handler.h2
-rw-r--r--sql/mdl.h5
-rw-r--r--sql/rpl_parallel.cc2
-rw-r--r--sql/sql_insert.cc4
-rw-r--r--sql/sql_sequence.cc5
-rw-r--r--sql/table.cc25
-rw-r--r--sql/xa.cc3
-rw-r--r--storage/innobase/handler/ha_innodb.cc129
-rw-r--r--storage/innobase/include/row0ins.h3
-rw-r--r--storage/innobase/include/row0upd.h45
-rw-r--r--storage/innobase/row/row0mysql.cc58
-rw-r--r--storage/innobase/row/row0upd.cc83
-rw-r--r--storage/innobase/trx/trx0trx.cc9
-rw-r--r--storage/maria/ha_maria.cc4
-rw-r--r--storage/maria/ha_maria.h1
24 files changed, 647 insertions, 182 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter_charset.result b/mysql-test/suite/innodb/r/instant_alter_charset.result
index cbb49819bfe..9e7dab8f7b4 100644
--- a/mysql-test/suite/innodb/r/instant_alter_charset.result
+++ b/mysql-test/suite/innodb/r/instant_alter_charset.result
@@ -1929,3 +1929,66 @@ KEY a_idx(a(1))
INSERT INTO t VALUES (1, 'something in the air');
ALTER TABLE t MODIFY a text CHARSET utf8mb4;
DROP TABLE t;
+#
+# MDEV-22899: Assertion `field->col->is_binary() || field->prefix_len % field->col->mbmaxlen == 0' failed in dict_index_add_to_cache
+#
+CREATE TABLE t1 (
+a text CHARACTER SET utf8 DEFAULT NULL,
+KEY a_key (a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+CREATE TABLE t1 (
+a text CHARACTER SET utf8 DEFAULT NULL,
+b int,
+KEY a_key (b, a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+CREATE TABLE t1 (
+a char(200) CHARACTER SET utf8 DEFAULT NULL,
+KEY a_key (a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+CREATE TABLE t1 (
+a char(200) CHARACTER SET utf8 DEFAULT NULL,
+b int,
+KEY a_key (b, a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+CREATE TABLE t1 (
+a varchar(200) CHARACTER SET utf8 DEFAULT NULL,
+KEY a_key (a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+CREATE TABLE t1 (
+a varchar(200) CHARACTER SET utf8 DEFAULT NULL,
+b int,
+KEY a_key (b, a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+CREATE TABLE t1 (
+a varchar(2000) CHARACTER SET utf8 DEFAULT NULL,
+KEY a_key (a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+CREATE TABLE t1 (
+a varchar(2000) CHARACTER SET utf8 DEFAULT NULL,
+b int,
+KEY a_key (b, a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/t/instant_alter_charset.test b/mysql-test/suite/innodb/t/instant_alter_charset.test
index 270db2d6462..b14c7861c25 100644
--- a/mysql-test/suite/innodb/t/instant_alter_charset.test
+++ b/mysql-test/suite/innodb/t/instant_alter_charset.test
@@ -730,3 +730,76 @@ INSERT INTO t VALUES (1, 'something in the air');
ALTER TABLE t MODIFY a text CHARSET utf8mb4;
DROP TABLE t;
+
+
+--echo #
+--echo # MDEV-22899: Assertion `field->col->is_binary() || field->prefix_len % field->col->mbmaxlen == 0' failed in dict_index_add_to_cache
+--echo #
+
+CREATE TABLE t1 (
+ a text CHARACTER SET utf8 DEFAULT NULL,
+ KEY a_key (a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ a text CHARACTER SET utf8 DEFAULT NULL,
+ b int,
+ KEY a_key (b, a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ a char(200) CHARACTER SET utf8 DEFAULT NULL,
+ KEY a_key (a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ a char(200) CHARACTER SET utf8 DEFAULT NULL,
+ b int,
+ KEY a_key (b, a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ a varchar(200) CHARACTER SET utf8 DEFAULT NULL,
+ KEY a_key (a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ a varchar(200) CHARACTER SET utf8 DEFAULT NULL,
+ b int,
+ KEY a_key (b, a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ a varchar(2000) CHARACTER SET utf8 DEFAULT NULL,
+ KEY a_key (a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ a varchar(2000) CHARACTER SET utf8 DEFAULT NULL,
+ b int,
+ KEY a_key (b, a(1))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+INSERT INTO t1 VALUES ();
+ALTER TABLE t1 MODIFY a text DEFAULT NULL;
+DROP TABLE t1;
diff --git a/mysql-test/suite/rpl/r/parallel_backup.result b/mysql-test/suite/rpl/r/parallel_backup.result
new file mode 100644
index 00000000000..d87c61f2d0f
--- /dev/null
+++ b/mysql-test/suite/rpl/r/parallel_backup.result
@@ -0,0 +1,40 @@
+include/master-slave.inc
+[connection master]
+#
+# MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel
+# replication
+#
+connection master;
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb;
+connection slave;
+include/stop_slave.inc
+SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode;
+SET @@global.slave_parallel_threads= 2;
+SET @@global.slave_parallel_mode = 'optimistic';
+connection master;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+connect aux_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
+BEGIN;
+INSERT INTO t1 VALUES (1);
+connection slave;
+include/start_slave.inc
+connection aux_slave;
+connect backup_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
+BACKUP STAGE START;
+BACKUP STAGE BLOCK_COMMIT;
+connection aux_slave;
+ROLLBACK;
+connection backup_slave;
+BACKUP STAGE END;
+connection slave;
+include/diff_tables.inc [master:t1,slave:t1]
+connection slave;
+include/stop_slave.inc
+SET @@global.slave_parallel_threads= @old_parallel_threads;
+SET @@global.slave_parallel_mode = @old_parallel_mode;
+include/start_slave.inc
+connection server_1;
+DROP TABLE t1;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/parallel_backup.test b/mysql-test/suite/rpl/t/parallel_backup.test
new file mode 100644
index 00000000000..6ed182c024b
--- /dev/null
+++ b/mysql-test/suite/rpl/t/parallel_backup.test
@@ -0,0 +1,75 @@
+--source include/have_innodb.inc
+# The test is not format specific, MIXED is required to optimize testing time
+--source include/have_binlog_format_mixed.inc
+--source include/master-slave.inc
+
+--echo #
+--echo # MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel
+--echo # replication
+--echo #
+
+--connection master
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb;
+
+--sync_slave_with_master
+--source include/stop_slave.inc
+SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode;
+SET @@global.slave_parallel_threads= 2;
+SET @@global.slave_parallel_mode = 'optimistic';
+
+--connection master
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+--save_master_pos
+
+# The plot:
+# Block the 1st of two workers and, at waiting-for-prior-commit by the 2nd,
+# issue BACKUP commands.
+# BLOCK_COMMIT may hang so it is --send.
+# Release the 1st worker to observe a deadlock unless its fixed.
+
+--connect (aux_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,)
+BEGIN;
+# block the 1st worker and wait for the 2nd ready to commit
+INSERT INTO t1 VALUES (1);
+
+--connection slave
+--source include/start_slave.inc
+
+--connection aux_slave
+--let $wait_condition= SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit"
+--source include/wait_condition.inc
+
+# While the 1st worker is locked out run backup
+--connect (backup_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,)
+BACKUP STAGE START;
+--send BACKUP STAGE BLOCK_COMMIT
+
+# release the 1st work
+--connection aux_slave
+--sleep 1
+ROLLBACK;
+
+--connection backup_slave
+--reap
+BACKUP STAGE END;
+
+--connection slave
+--sync_with_master
+
+--let $diff_tables= master:t1,slave:t1
+--source include/diff_tables.inc
+
+
+# Clean up.
+--connection slave
+--source include/stop_slave.inc
+SET @@global.slave_parallel_threads= @old_parallel_threads;
+SET @@global.slave_parallel_mode = @old_parallel_mode;
+--source include/start_slave.inc
+
+--connection server_1
+DROP TABLE t1;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/sql_sequence/kill.result b/mysql-test/suite/sql_sequence/kill.result
new file mode 100644
index 00000000000..6d966254de3
--- /dev/null
+++ b/mysql-test/suite/sql_sequence/kill.result
@@ -0,0 +1,12 @@
+#
+# MDEV-16929 Assertion ... in close_thread_tables upon killing connection
+# running SHOW on sequence
+#
+CREATE SEQUENCE s ENGINE=InnoDB;
+RENAME TABLE s TO s1;
+connect con1,localhost,root,,test;
+SHOW CREATE SEQUENCE s1;
+connection default;
+KILL thread_id;
+connection default;
+drop sequence s1;
diff --git a/mysql-test/suite/sql_sequence/kill.test b/mysql-test/suite/sql_sequence/kill.test
new file mode 100644
index 00000000000..9caebc57f12
--- /dev/null
+++ b/mysql-test/suite/sql_sequence/kill.test
@@ -0,0 +1,20 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-16929 Assertion ... in close_thread_tables upon killing connection
+--echo # running SHOW on sequence
+--echo #
+
+CREATE SEQUENCE s ENGINE=InnoDB;
+RENAME TABLE s TO s1;
+--connect (con1,localhost,root,,test)
+--let $conid= `SELECT CONNECTION_ID()`
+--send
+ SHOW CREATE SEQUENCE s1;
+--connection default
+--replace_result $conid thread_id
+--eval KILL $conid
+
+# Cleanup
+--connection default
+drop sequence s1;
diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result
index f7901d11d2a..cd26c341113 100644
--- a/mysql-test/suite/versioning/r/update.result
+++ b/mysql-test/suite/versioning/r/update.result
@@ -319,3 +319,34 @@ create or replace table t1 (f point, key(f)) with system versioning engine=myisa
update t1 set f = null where f = 'foo';
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
drop table t1;
+#
+# MDEV-22061 InnoDB: Assertion of missing row in sec index row_start upon REPLACE on a system-versioned table
+#
+create or replace table t1 (
+a int,
+b int,
+row_start bigint(20) unsigned generated always as row start,
+row_end bigint(20) unsigned generated always as row end,
+unique key (b,row_end),
+key (row_start),
+period for system_time (row_start,row_end)
+) engine=innodb with system versioning;
+insert into t1 (a, b) values (1, 2);
+replace into t1 (a, b) values (3, 2);
+replace into t1 (a, b) values (4, 2);
+drop table t1;
+#
+# MDEV-20661 Virtual fields are not recalculated on system fields value assignment
+#
+create table t1 (
+a int,
+row_start SYS_DATATYPE as row start invisible,
+row_end SYS_DATATYPE as row end invisible,
+period for system_time (row_start, row_end),
+v1 bigint unsigned as (a ^ row_start) unique,
+v2 bigint unsigned as (a ^ row_end) unique
+) engine=innodb with system versioning;
+insert into t1 (a) values (1), (2);
+update ignore t1 set a= 3;
+delete history from t1;
+drop table t1;
diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test
index 5b0a9eb5c42..06f81ea9064 100644
--- a/mysql-test/suite/versioning/t/update.test
+++ b/mysql-test/suite/versioning/t/update.test
@@ -245,4 +245,45 @@ update t1 set f = null where f = 'foo';
# cleanup
drop table t1;
+--echo #
+--echo # MDEV-22061 InnoDB: Assertion of missing row in sec index row_start upon REPLACE on a system-versioned table
+--echo #
+create or replace table t1 (
+ a int,
+ b int,
+ row_start bigint(20) unsigned generated always as row start,
+ row_end bigint(20) unsigned generated always as row end,
+ unique key (b,row_end),
+ key (row_start),
+ period for system_time (row_start,row_end)
+) engine=innodb with system versioning;
+
+insert into t1 (a, b) values (1, 2);
+replace into t1 (a, b) values (3, 2);
+replace into t1 (a, b) values (4, 2);
+
+# cleanup
+drop table t1;
+
+--echo #
+--echo # MDEV-20661 Virtual fields are not recalculated on system fields value assignment
+--echo #
+
+replace_result $sys_datatype_expl SYS_DATATYPE;
+eval create table t1 (
+ a int,
+ row_start $sys_datatype_expl as row start invisible,
+ row_end $sys_datatype_expl as row end invisible,
+ period for system_time (row_start, row_end),
+ v1 bigint unsigned as (a ^ row_start) unique,
+ v2 bigint unsigned as (a ^ row_end) unique
+) engine=innodb with system versioning;
+
+insert into t1 (a) values (1), (2);
+update ignore t1 set a= 3;
+delete history from t1;
+
+# cleanup
+drop table t1;
+
source suite/versioning/common_finish.inc;
diff --git a/sql/handler.cc b/sql/handler.cc
index ace58869145..48bae864125 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -188,7 +188,7 @@ private:
static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans,
- bool is_real_trans);
+ bool is_real_trans, bool rw_trans);
static plugin_ref ha_default_plugin(THD *thd)
@@ -1621,39 +1621,9 @@ int ha_commit_trans(THD *thd, bool all)
/* rw_trans is TRUE when we in a transaction changing data */
bool rw_trans= is_real_trans &&
(rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U));
- MDL_request mdl_request;
- mdl_request.ticket= 0;
DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d",
is_real_trans, rw_trans, rw_ha_count));
- /*
- We need to test maria_hton because of plugin_innodb.test that changes
- the plugin table to innodb and thus plugin_load will call
- mysql_close_tables() which calls trans_commit_trans() with maria_hton = 0
- */
- if (rw_trans)
- {
- /*
- Acquire a metadata lock which will ensure that COMMIT is blocked
- by an active FLUSH TABLES WITH READ LOCK (and vice versa:
- COMMIT in progress blocks FTWRL).
-
- We allow the owner of FTWRL to COMMIT; we assume that it knows
- what it does.
- */
- MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
- MDL_EXPLICIT);
-
- if (!WSREP(thd) &&
- thd->mdl_context.acquire_lock(&mdl_request,
- thd->variables.lock_wait_timeout))
- {
- ha_rollback_trans(thd, all);
- DBUG_RETURN(1);
- }
-
- DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock");
- }
if (rw_trans &&
opt_readonly &&
!(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) &&
@@ -1693,7 +1663,7 @@ int ha_commit_trans(THD *thd, bool all)
// Here, the call will not commit inside InnoDB. It is only working
// around closing thd->transaction.stmt open by TR_table::open().
if (all)
- commit_one_phase_2(thd, false, &thd->transaction->stmt, false);
+ commit_one_phase_2(thd, false, &thd->transaction->stmt, false, false);
}
}
#endif
@@ -1713,7 +1683,7 @@ int ha_commit_trans(THD *thd, bool all)
goto wsrep_err;
}
#endif /* WITH_WSREP */
- error= ha_commit_one_phase(thd, all);
+ error= ha_commit_one_phase(thd, all, rw_trans);
#ifdef WITH_WSREP
// Here in case of error we must return 2 for inconsistency
if (run_wsrep_hooks && !error)
@@ -1750,7 +1720,7 @@ int ha_commit_trans(THD *thd, bool all)
if (!is_real_trans)
{
- error= commit_one_phase_2(thd, all, trans, is_real_trans);
+ error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans);
goto done;
}
@@ -1784,7 +1754,7 @@ int ha_commit_trans(THD *thd, bool all)
DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order");
DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
- error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0;
+ error= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans) ? 2 : 0;
#ifdef WITH_WSREP
if (run_wsrep_hooks &&
(error || (error = wsrep_after_commit(thd, all))))
@@ -1854,16 +1824,6 @@ err:
thd->rgi_slave->is_parallel_exec);
}
end:
- if (mdl_request.ticket)
- {
- /*
- We do not always immediately release transactional locks
- after ha_commit_trans() (see uses of ha_enable_transaction()),
- thus we release the commit blocker lock as soon as it's
- not needed.
- */
- thd->mdl_context.release_lock(mdl_request.ticket);
- }
#ifdef WITH_WSREP
if (wsrep_is_active(thd) && is_real_trans && !error &&
(rw_ha_count == 0 || all) &&
@@ -1879,6 +1839,7 @@ end:
/**
@note
This function does not care about global read lock. A caller should.
+ However backup locks are handled in commit_one_phase_2.
@param[in] all Is set in case of explicit commit
(COMMIT statement), or implicit commit
@@ -1887,7 +1848,7 @@ end:
autocommit=1.
*/
-int ha_commit_one_phase(THD *thd, bool all)
+int ha_commit_one_phase(THD *thd, bool all, bool rw_trans)
{
THD_TRANS *trans=all ? &thd->transaction->all : &thd->transaction->stmt;
/*
@@ -1913,20 +1874,48 @@ int ha_commit_one_phase(THD *thd, bool all)
if ((res= thd->wait_for_prior_commit()))
DBUG_RETURN(res);
}
- res= commit_one_phase_2(thd, all, trans, is_real_trans);
+ res= commit_one_phase_2(thd, all, trans, is_real_trans, rw_trans);
DBUG_RETURN(res);
}
static int
-commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
+commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans,
+ bool rw_trans)
{
int error= 0;
uint count= 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
+ MDL_request mdl_request;
+ mdl_request.ticket= 0;
DBUG_ENTER("commit_one_phase_2");
if (is_real_trans)
DEBUG_SYNC(thd, "commit_one_phase_2");
+
+ if (rw_trans)
+ {
+ /*
+ Acquire a metadata lock which will ensure that COMMIT is blocked
+ by an active FLUSH TABLES WITH READ LOCK (and vice versa:
+ COMMIT in progress blocks FTWRL).
+
+ We allow the owner of FTWRL to COMMIT; we assume that it knows
+ what it does.
+ */
+ MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+ MDL_EXPLICIT);
+
+ if (!WSREP(thd) &&
+ thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), 1);
+ ha_rollback_trans(thd, all);
+ DBUG_RETURN(1);
+ }
+ DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock");
+ }
+
if (ha_info)
{
for (; ha_info; ha_info= ha_info_next)
@@ -1955,6 +1944,17 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
#endif
}
}
+ if (mdl_request.ticket)
+ {
+ /*
+ We do not always immediately release transactional locks
+ after ha_commit_trans() (see uses of ha_enable_transaction()),
+ thus we release the commit blocker lock as soon as it's
+ not needed.
+ */
+ thd->mdl_context.release_lock(mdl_request.ticket);
+ }
+
/* Free resources and perform other cleanup even for 'empty' transactions. */
if (is_real_trans)
{
diff --git a/sql/handler.h b/sql/handler.h
index e8315b6ad9a..1acf816dcb9 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -5176,7 +5176,7 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache);
/* transactions: interface to handlerton functions */
int ha_start_consistent_snapshot(THD *thd);
int ha_commit_or_rollback_by_xid(XID *xid, bool commit);
-int ha_commit_one_phase(THD *thd, bool all);
+int ha_commit_one_phase(THD *thd, bool all, bool rw_trans);
int ha_commit_trans(THD *thd, bool all);
int ha_rollback_trans(THD *thd, bool all);
int ha_prepare(THD *thd);
diff --git a/sql/mdl.h b/sql/mdl.h
index dd10b3a45d0..f6b7154fba0 100644
--- a/sql/mdl.h
+++ b/sql/mdl.h
@@ -124,6 +124,8 @@ public:
*/
enum enum_mdl_type {
+ /* This means that the MDL_request is not initialized */
+ MDL_NOT_INITIALIZED= -1,
/*
An intention exclusive metadata lock (IX). Used only for scoped locks.
Owner of this type of lock can acquire upgradable exclusive locks on
@@ -599,12 +601,13 @@ public:
*/
MDL_request& operator=(const MDL_request &)
{
+ type= MDL_NOT_INITIALIZED;
ticket= NULL;
/* Do nothing, in particular, don't try to copy the key. */
return *this;
}
/* Another piece of ugliness for TABLE_LIST constructor */
- MDL_request() {}
+ MDL_request(): type(MDL_NOT_INITIALIZED), ticket(NULL) {}
MDL_request(const MDL_request *rhs)
:type(rhs->type),
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 94882230682..c12573f817f 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -1053,10 +1053,10 @@ handle_rpl_parallel_thread(void *arg)
server_threads.insert(thd);
set_current_thd(thd);
pthread_detach_this_thread();
+ thd->store_globals();
thd->init_for_queries();
thd->variables.binlog_annotate_row_events= 0;
init_thr_lock();
- thd->store_globals();
thd->system_thread= SYSTEM_THREAD_SLAVE_SQL;
thd->security_ctx->skip_grants();
thd->variables.max_allowed_packet= slave_max_allowed_packet;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 31badbe2aba..d25410292ef 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1717,6 +1717,10 @@ int vers_insert_history_row(TABLE *table)
if (row_start->cmp(row_start->ptr, row_end->ptr) >= 0)
return 0;
+ if (table->vfield &&
+ table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_READ))
+ return HA_ERR_GENERIC;
+
return table->file->ha_write_row(table->record[0]);
}
diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc
index c0925da59e1..b9d500d463c 100644
--- a/sql/sql_sequence.cc
+++ b/sql/sql_sequence.cc
@@ -1,5 +1,6 @@
/*
Copyright (c) 2017, MariaDB Corporation, Alibaba Corporation
+ Copyrgiht (c) 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -483,6 +484,10 @@ int SEQUENCE::read_initial_values(TABLE *table)
if (mdl_lock_used)
thd->mdl_context.release_lock(mdl_request.ticket);
write_unlock(table);
+
+ if (!has_active_transaction && !thd->transaction->stmt.is_empty() &&
+ !thd->in_sub_stmt)
+ trans_commit_stmt(thd);
DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT);
}
DBUG_ASSERT(table->reginfo.lock_type == TL_READ);
diff --git a/sql/table.cc b/sql/table.cc
index 32d0ee6f538..d7ea9d447fa 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -8809,29 +8809,24 @@ void TABLE::vers_update_fields()
bitmap_set_bit(write_set, vers_start_field()->field_index);
bitmap_set_bit(write_set, vers_end_field()->field_index);
- if (versioned(VERS_TIMESTAMP))
+ if (!vers_write)
{
- if (!vers_write)
- {
- file->column_bitmaps_signal();
- return;
- }
- if (vers_start_field()->store_timestamp(in_use->query_start(),
- in_use->query_start_sec_part()))
- DBUG_ASSERT(0);
+ file->column_bitmaps_signal();
+ return;
}
- else
+
+ if (versioned(VERS_TIMESTAMP) &&
+ vers_start_field()->store_timestamp(in_use->query_start(),
+ in_use->query_start_sec_part()))
{
- if (!vers_write)
- {
- file->column_bitmaps_signal();
- return;
- }
+ DBUG_ASSERT(0);
}
vers_end_field()->set_max();
bitmap_set_bit(read_set, vers_end_field()->field_index);
file->column_bitmaps_signal();
+ if (vfield)
+ update_virtual_fields(file, VCOL_UPDATE_FOR_READ);
}
diff --git a/sql/xa.cc b/sql/xa.cc
index 68e6e67fa0b..7d6d7187bce 100644
--- a/sql/xa.cc
+++ b/sql/xa.cc
@@ -689,7 +689,8 @@ bool trans_xa_commit(THD *thd)
{
DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
- if ((res= MY_TEST(ha_commit_one_phase(thd, 1))))
+ res= MY_TEST(ha_commit_one_phase(thd, 1, 1));
+ if (res)
my_error(ER_XAER_RMERR, MYF(0));
else
{
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index b03900d76fa..04645ba025b 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -21150,39 +21150,49 @@ ha_innobase::can_convert_varstring(const Field_varstring* field,
return true;
}
-bool
-ha_innobase::can_convert_blob(const Field_blob* field,
- const Column_definition& new_type) const
+static bool is_part_of_a_key(const Field_blob *field)
{
- if (new_type.type_handler() != field->type_handler()) {
- return false;
- }
+ const TABLE_SHARE *s= field->table->s;
- if (!new_type.compression_method() != !field->compression_method()) {
- return false;
- }
+ for (uint i= 0; i < s->keys; i++)
+ {
+ const KEY &key= s->key_info[i];
+ for (uint j= 0; j < key.user_defined_key_parts; j++)
+ {
+ const KEY_PART_INFO &info= key.key_part[j];
+ if (info.field->field_index == field->field_index)
+ return true;
+ }
+ }
- if (new_type.pack_length != field->pack_length()) {
- return false;
- }
+ return false;
+}
- if (new_type.charset != field->charset()) {
- Charset field_cs(field->charset());
- if (!field_cs.encoding_allows_reinterpret_as(
- new_type.charset)) {
- return false;
- }
+bool ha_innobase::can_convert_blob(const Field_blob *field,
+ const Column_definition &new_type) const
+{
+ if (new_type.type_handler() != field->type_handler())
+ return false;
- if (!field_cs.eq_collation_specific_names(new_type.charset)) {
- bool is_part_of_a_key
- = !field->part_of_key.is_clear_all();
- return !is_part_of_a_key;
- }
+ if (!new_type.compression_method() != !field->compression_method())
+ return false;
- return true;
- }
+ if (new_type.pack_length != field->pack_length())
+ return false;
- return true;
+ if (new_type.charset != field->charset())
+ {
+ Charset field_cs(field->charset());
+ if (!field_cs.encoding_allows_reinterpret_as(new_type.charset))
+ return false;
+
+ if (!field_cs.eq_collation_specific_names(new_type.charset))
+ return !is_part_of_a_key(field);
+
+ return true;
+ }
+
+ return true;
}
Compare_keys ha_innobase::compare_key_parts(
@@ -21808,3 +21818,70 @@ ib_push_frm_error(
break;
}
}
+
+/** Writes 8 bytes to nth tuple field
+@param[in] tuple where to write
+@param[in] nth index in tuple
+@param[in] data what to write
+@param[in] buf field data buffer */
+static void set_tuple_col_8(dtuple_t *tuple, int col, uint64_t data, byte *buf)
+{
+ dfield_t *dfield= dtuple_get_nth_field(tuple, col);
+ ut_ad(dfield->type.len == 8);
+ if (dfield->len == UNIV_SQL_NULL)
+ {
+ dfield_set_data(dfield, buf, 8);
+ }
+ ut_ad(dfield->len == dfield->type.len && dfield->data);
+ mach_write_to_8(dfield->data, data);
+}
+
+void ins_node_t::vers_update_end(row_prebuilt_t *prebuilt, bool history_row)
+{
+ ut_ad(prebuilt->ins_node == this);
+ trx_t *trx= prebuilt->trx;
+#ifndef DBUG_OFF
+ ut_ad(table->vers_start != table->vers_end);
+ const mysql_row_templ_t *t= prebuilt->get_template_by_col(table->vers_end);
+ ut_ad(t);
+ ut_ad(t->mysql_col_len == 8);
+#endif
+
+ if (history_row)
+ {
+ set_tuple_col_8(row, table->vers_end, trx->id, vers_end_buf);
+ }
+ else /* ROW_INS_VERSIONED */
+ {
+ set_tuple_col_8(row, table->vers_end, TRX_ID_MAX, vers_end_buf);
+#ifndef DBUG_OFF
+ t= prebuilt->get_template_by_col(table->vers_start);
+ ut_ad(t);
+ ut_ad(t->mysql_col_len == 8);
+#endif
+ set_tuple_col_8(row, table->vers_start, trx->id, vers_start_buf);
+ }
+ dict_index_t *clust_index= dict_table_get_first_index(table);
+ THD *thd= trx->mysql_thd;
+ TABLE *mysql_table= prebuilt->m_mysql_table;
+ mem_heap_t *local_heap= NULL;
+ for (ulint col_no= 0; col_no < dict_table_get_n_v_cols(table); col_no++)
+ {
+
+ const dict_v_col_t *v_col= dict_table_get_nth_v_col(table, col_no);
+ for (ulint i= 0; i < unsigned(v_col->num_base); i++)
+ {
+ dict_col_t *base_col= v_col->base_col[i];
+ if (base_col->ind == table->vers_end)
+ {
+ innobase_get_computed_value(row, v_col, clust_index, &local_heap,
+ table->heap, NULL, thd, mysql_table,
+ mysql_table->record[0], NULL, NULL, NULL);
+ }
+ }
+ }
+ if (local_heap)
+ {
+ mem_heap_free(local_heap);
+ }
+}
diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h
index 95f4388902d..34427dc6dc7 100644
--- a/storage/innobase/include/row0ins.h
+++ b/storage/innobase/include/row0ins.h
@@ -163,6 +163,8 @@ row_ins_step(
#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
inserted */
+struct row_prebuilt_t;
+
/** Insert node structure */
struct ins_node_t
{
@@ -203,6 +205,7 @@ struct ins_node_t
entry_list and sys fields are stored here;
if this is NULL, entry list should be created
and buffers for sys fields in row allocated */
+ void vers_update_end(row_prebuilt_t *prebuilt, bool history_row);
};
/** Create an insert object.
diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h
index 65f70be7134..f9d949fc2d7 100644
--- a/storage/innobase/include/row0upd.h
+++ b/storage/innobase/include/row0upd.h
@@ -354,7 +354,32 @@ struct upd_t{
fields[n_fields++] = field;
}
- /** Determine if the given field_no is modified.
+ void remove_element(ulint i)
+ {
+ ut_ad(n_fields > 0);
+ ut_ad(i < n_fields);
+ while (i < n_fields - 1)
+ {
+ fields[i]= fields[i + 1];
+ i++;
+ }
+ n_fields--;
+ }
+
+ bool remove(const ulint field_no)
+ {
+ for (ulint i= 0; i < n_fields; ++i)
+ {
+ if (field_no == fields[i].field_no)
+ {
+ remove_element(i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Determine if the given field_no is modified.
@return true if modified, false otherwise. */
bool is_modified(uint16_t field_no) const
{
@@ -494,25 +519,25 @@ private:
make_versioned_delete().
@param[in] trx transaction
@param[in] vers_sys_idx table->row_start or table->row_end */
- void make_versioned_helper(const trx_t* trx, ulint idx);
+ void vers_update_fields(const trx_t *trx, ulint idx);
public:
/** Also set row_start = CURRENT_TIMESTAMP/trx->id
@param[in] trx transaction */
- void make_versioned_update(const trx_t* trx)
- {
- make_versioned_helper(trx, table->vers_start);
- }
+ void vers_make_update(const trx_t *trx)
+ {
+ vers_update_fields(trx, table->vers_start);
+ }
/** Only set row_end = CURRENT_TIMESTAMP/trx->id.
Do not touch other fields at all.
@param[in] trx transaction */
- void make_versioned_delete(const trx_t* trx)
- {
+ void vers_make_delete(const trx_t *trx)
+ {
update->n_fields = 0;
is_delete = VERSIONED_DELETE;
- make_versioned_helper(trx, table->vers_end);
- }
+ vers_update_fields(trx, table->vers_end);
+ }
};
#define UPD_NODE_MAGIC_N 1579975
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 20f06fc5444..296c273a779 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -1331,23 +1331,6 @@ row_mysql_get_table_status(
return(err);
}
-/** Writes 8 bytes to nth tuple field
-@param[in] tuple where to write
-@param[in] nth index in tuple
-@param[in] data what to write
-@param[in] buf field data buffer */
-static
-void
-set_tuple_col_8(dtuple_t* tuple, int col, uint64_t data, byte* buf) {
- dfield_t* dfield = dtuple_get_nth_field(tuple, col);
- ut_ad(dfield->type.len == 8);
- if (dfield->len == UNIV_SQL_NULL) {
- dfield_set_data(dfield, buf, 8);
- }
- ut_ad(dfield->len == dfield->type.len && dfield->data);
- mach_write_to_8(dfield->data, data);
-}
-
/** Does an insert for MySQL.
@param[in] mysql_rec row in the MySQL format
@param[in,out] prebuilt prebuilt struct in MySQL handle
@@ -1415,29 +1398,8 @@ row_insert_for_mysql(
&blob_heap);
if (ins_mode != ROW_INS_NORMAL) {
-#ifndef DBUG_OFF
- ut_ad(table->vers_start != table->vers_end);
- const mysql_row_templ_t* t
- = prebuilt->get_template_by_col(table->vers_end);
- ut_ad(t);
- ut_ad(t->mysql_col_len == 8);
-#endif
-
- if (ins_mode == ROW_INS_HISTORICAL) {
- set_tuple_col_8(node->row, table->vers_end, trx->id,
- node->vers_end_buf);
- } else /* ROW_INS_VERSIONED */ {
- set_tuple_col_8(node->row, table->vers_end, TRX_ID_MAX,
- node->vers_end_buf);
-#ifndef DBUG_OFF
- t = prebuilt->get_template_by_col(table->vers_start);
- ut_ad(t);
- ut_ad(t->mysql_col_len == 8);
-#endif
- set_tuple_col_8(node->row, table->vers_start, trx->id,
- node->vers_start_buf);
- }
- }
+ node->vers_update_end(prebuilt, ins_mode == ROW_INS_HISTORICAL);
+ }
savept = trx_savept_take(trx);
@@ -1871,10 +1833,10 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
if (prebuilt->versioned_write) {
if (node->is_delete == VERSIONED_DELETE) {
- node->make_versioned_delete(trx);
- } else if (node->update->affects_versioned()) {
- node->make_versioned_update(trx);
- }
+ node->vers_make_delete(trx);
+ } else if (node->update->affects_versioned()) {
+ node->vers_make_update(trx);
+ }
}
for (;;) {
@@ -2230,14 +2192,14 @@ row_update_cascade_for_mysql(
if (table->versioned()) {
if (node->is_delete == PLAIN_DELETE) {
- node->make_versioned_delete(trx);
- } else if (node->update->affects_versioned()) {
+ node->vers_make_delete(trx);
+ } else if (node->update->affects_versioned()) {
dberr_t err = row_update_vers_insert(thr, node);
if (err != DB_SUCCESS) {
return err;
}
- node->make_versioned_update(trx);
- }
+ node->vers_make_update(trx);
+ }
}
for (;;) {
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index fe81cb46916..2639f3ec7ea 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -3173,34 +3173,59 @@ Supposed to be called only by make_versioned_update() and
make_versioned_delete().
@param[in] trx transaction
@param[in] vers_sys_idx table->row_start or table->row_end */
-void upd_node_t::make_versioned_helper(const trx_t* trx, ulint idx)
+void upd_node_t::vers_update_fields(const trx_t *trx, ulint idx)
{
- ut_ad(in_mysql_interface); // otherwise needs to recalculate
- // node->cmpl_info
- ut_ad(idx == table->vers_start || idx == table->vers_end);
-
- dict_index_t* clust_index = dict_table_get_first_index(table);
-
- /* row_create_update_node_for_mysql() pre-allocated this much.
- At least one PK column always remains unchanged. */
- ut_ad(update->n_fields < ulint(table->n_cols + table->n_v_cols));
-
- update->n_fields++;
- upd_field_t* ufield = upd_get_nth_field(update, update->n_fields - 1);
- const dict_col_t* col = dict_table_get_nth_col(table, idx);
-
- upd_field_set_field_no(ufield, static_cast<uint16_t>(
- dict_col_get_clust_pos(
- col, clust_index)),
- clust_index);
-
- char* where = reinterpret_cast<char*>(update->vers_sys_value);
- if (col->vers_native()) {
- mach_write_to_8(where, trx->id);
- } else {
- thd_get_query_start_data(trx->mysql_thd, where);
- }
-
- dfield_set_data(&ufield->new_val, update->vers_sys_value, col->len);
+ ut_ad(in_mysql_interface); // otherwise needs to recalculate node->cmpl_info
+ ut_ad(idx == table->vers_start || idx == table->vers_end);
+
+ dict_index_t *clust_index= dict_table_get_first_index(table);
+ const dict_col_t *col= dict_table_get_nth_col(table, idx);
+ ulint field_no= dict_col_get_clust_pos(col, clust_index);
+ upd_field_t *ufield;
+
+ for (ulint i= 0; i < update->n_fields; ++i)
+ {
+ if (update->fields[i].field_no == field_no)
+ {
+ ufield= &update->fields[i];
+ goto skip_append;
+ }
+ }
+
+ /* row_create_update_node_for_mysql() pre-allocated this much.
+ At least one PK column always remains unchanged. */
+ ut_ad(update->n_fields < ulint(table->n_cols + table->n_v_cols));
+
+ update->n_fields++;
+ ufield= upd_get_nth_field(update, update->n_fields - 1);
+ upd_field_set_field_no(ufield, static_cast<uint16_t>(field_no), clust_index);
+
+skip_append:
+ char *where= reinterpret_cast<char *>(update->vers_sys_value);
+ if (col->vers_native())
+ mach_write_to_8(where, trx->id);
+ else
+ thd_get_query_start_data(trx->mysql_thd, where);
+
+ dfield_set_data(&ufield->new_val, update->vers_sys_value, col->len);
+
+ for (ulint col_no= 0; col_no < dict_table_get_n_v_cols(table); col_no++)
+ {
+ const dict_v_col_t *v_col= dict_table_get_nth_v_col(table, col_no);
+ if (!v_col->m_col.ord_part)
+ continue;
+ for (ulint i= 0; i < unsigned(v_col->num_base); i++)
+ {
+ dict_col_t *base_col= v_col->base_col[i];
+ if (base_col->ind == col->ind)
+ {
+ /* Virtual column depends on system field value
+ which we updated above. Remove it from update
+ vector, so it is recalculated in
+ row_upd_store_v_row() (see !update branch). */
+ update->remove(v_col->v_pos);
+ break;
+ }
+ }
+ }
}
-
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 03e60d80d5b..fb594b0b099 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -1272,7 +1272,8 @@ trx_update_mod_tables_timestamp(
dict_table_t* table = it->first;
table->update_time = now;
#ifdef UNIV_DEBUG
- if (preserve_tables || table->get_ref_count()) {
+ if (preserve_tables || table->get_ref_count()
+ || UT_LIST_GET_LEN(table->locks)) {
/* do not evict when committing DDL operations
or if some other transaction is holding the
table handle */
@@ -1281,7 +1282,11 @@ trx_update_mod_tables_timestamp(
/* recheck while holding the mutex that blocks
table->acquire() */
mutex_enter(&dict_sys.mutex);
- if (!table->get_ref_count()) {
+ mutex_enter(&lock_sys.mutex);
+ const bool do_evict = !table->get_ref_count()
+ && !UT_LIST_GET_LEN(table->locks);
+ mutex_exit(&lock_sys.mutex);
+ if (do_evict) {
dict_sys.remove(table, true);
}
mutex_exit(&dict_sys.mutex);
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index c257a2094f1..3c43595533f 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -2947,6 +2947,10 @@ static void reset_thd_trn(THD *thd, MARIA_HA *first_table)
DBUG_VOID_RETURN;
}
+bool ha_maria::has_active_transaction(THD *thd)
+{
+ return (maria_hton && THD_TRN);
+}
/**
Performs an implicit commit of the Maria transaction and creates a new
diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h
index bff7ace8813..ddf8fc6f229 100644
--- a/storage/maria/ha_maria.h
+++ b/storage/maria/ha_maria.h
@@ -158,6 +158,7 @@ public:
{
return file;
}
+ static bool has_active_transaction(THD *thd);
static int implicit_commit(THD *thd, bool new_trn);
/**
* Multi Range Read interface