Merge 10.4 into 10.5
This commit is contained in:
commit
4ec032b492
@ -1929,3 +1929,66 @@ KEY a_idx(a(1))
|
|||||||
INSERT INTO t VALUES (1, 'something in the air');
|
INSERT INTO t VALUES (1, 'something in the air');
|
||||||
ALTER TABLE t MODIFY a text CHARSET utf8mb4;
|
ALTER TABLE t MODIFY a text CHARSET utf8mb4;
|
||||||
DROP TABLE t;
|
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;
|
||||||
|
@ -730,3 +730,76 @@ INSERT INTO t VALUES (1, 'something in the air');
|
|||||||
ALTER TABLE t MODIFY a text CHARSET utf8mb4;
|
ALTER TABLE t MODIFY a text CHARSET utf8mb4;
|
||||||
|
|
||||||
DROP TABLE t;
|
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;
|
||||||
|
40
mysql-test/suite/rpl/r/parallel_backup.result
Normal file
40
mysql-test/suite/rpl/r/parallel_backup.result
Normal file
@ -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
|
75
mysql-test/suite/rpl/t/parallel_backup.test
Normal file
75
mysql-test/suite/rpl/t/parallel_backup.test
Normal file
@ -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
|
12
mysql-test/suite/sql_sequence/kill.result
Normal file
12
mysql-test/suite/sql_sequence/kill.result
Normal file
@ -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;
|
20
mysql-test/suite/sql_sequence/kill.test
Normal file
20
mysql-test/suite/sql_sequence/kill.test
Normal file
@ -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;
|
@ -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';
|
update t1 set f = null where f = 'foo';
|
||||||
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
|
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
|
||||||
drop table t1;
|
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;
|
||||||
|
@ -245,4 +245,45 @@ update t1 set f = null where f = 'foo';
|
|||||||
# cleanup
|
# cleanup
|
||||||
drop table t1;
|
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;
|
source suite/versioning/common_finish.inc;
|
||||||
|
@ -188,7 +188,7 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans,
|
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)
|
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 */
|
/* rw_trans is TRUE when we in a transaction changing data */
|
||||||
bool rw_trans= is_real_trans &&
|
bool rw_trans= is_real_trans &&
|
||||||
(rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U));
|
(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",
|
DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d",
|
||||||
is_real_trans, rw_trans, rw_ha_count));
|
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 &&
|
if (rw_trans &&
|
||||||
opt_readonly &&
|
opt_readonly &&
|
||||||
!(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) &&
|
!(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
|
// Here, the call will not commit inside InnoDB. It is only working
|
||||||
// around closing thd->transaction.stmt open by TR_table::open().
|
// around closing thd->transaction.stmt open by TR_table::open().
|
||||||
if (all)
|
if (all)
|
||||||
commit_one_phase_2(thd, false, &thd->transaction->stmt, false);
|
commit_one_phase_2(thd, false, &thd->transaction->stmt, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1713,7 +1683,7 @@ int ha_commit_trans(THD *thd, bool all)
|
|||||||
goto wsrep_err;
|
goto wsrep_err;
|
||||||
}
|
}
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
error= ha_commit_one_phase(thd, all);
|
error= ha_commit_one_phase(thd, all, rw_trans);
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
// Here in case of error we must return 2 for inconsistency
|
// Here in case of error we must return 2 for inconsistency
|
||||||
if (run_wsrep_hooks && !error)
|
if (run_wsrep_hooks && !error)
|
||||||
@ -1750,7 +1720,7 @@ int ha_commit_trans(THD *thd, bool all)
|
|||||||
|
|
||||||
if (!is_real_trans)
|
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;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1784,7 +1754,7 @@ int ha_commit_trans(THD *thd, bool all)
|
|||||||
DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order");
|
DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order");
|
||||||
DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
|
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
|
#ifdef WITH_WSREP
|
||||||
if (run_wsrep_hooks &&
|
if (run_wsrep_hooks &&
|
||||||
(error || (error = wsrep_after_commit(thd, all))))
|
(error || (error = wsrep_after_commit(thd, all))))
|
||||||
@ -1854,16 +1824,6 @@ err:
|
|||||||
thd->rgi_slave->is_parallel_exec);
|
thd->rgi_slave->is_parallel_exec);
|
||||||
}
|
}
|
||||||
end:
|
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
|
#ifdef WITH_WSREP
|
||||||
if (wsrep_is_active(thd) && is_real_trans && !error &&
|
if (wsrep_is_active(thd) && is_real_trans && !error &&
|
||||||
(rw_ha_count == 0 || all) &&
|
(rw_ha_count == 0 || all) &&
|
||||||
@ -1879,6 +1839,7 @@ end:
|
|||||||
/**
|
/**
|
||||||
@note
|
@note
|
||||||
This function does not care about global read lock. A caller should.
|
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
|
@param[in] all Is set in case of explicit commit
|
||||||
(COMMIT statement), or implicit commit
|
(COMMIT statement), or implicit commit
|
||||||
@ -1887,7 +1848,7 @@ end:
|
|||||||
autocommit=1.
|
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;
|
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()))
|
if ((res= thd->wait_for_prior_commit()))
|
||||||
DBUG_RETURN(res);
|
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);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
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;
|
int error= 0;
|
||||||
uint count= 0;
|
uint count= 0;
|
||||||
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
|
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");
|
DBUG_ENTER("commit_one_phase_2");
|
||||||
if (is_real_trans)
|
if (is_real_trans)
|
||||||
DEBUG_SYNC(thd, "commit_one_phase_2");
|
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)
|
if (ha_info)
|
||||||
{
|
{
|
||||||
for (; ha_info; ha_info= ha_info_next)
|
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
|
#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. */
|
/* Free resources and perform other cleanup even for 'empty' transactions. */
|
||||||
if (is_real_trans)
|
if (is_real_trans)
|
||||||
{
|
{
|
||||||
|
@ -5176,7 +5176,7 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache);
|
|||||||
/* transactions: interface to handlerton functions */
|
/* transactions: interface to handlerton functions */
|
||||||
int ha_start_consistent_snapshot(THD *thd);
|
int ha_start_consistent_snapshot(THD *thd);
|
||||||
int ha_commit_or_rollback_by_xid(XID *xid, bool commit);
|
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_commit_trans(THD *thd, bool all);
|
||||||
int ha_rollback_trans(THD *thd, bool all);
|
int ha_rollback_trans(THD *thd, bool all);
|
||||||
int ha_prepare(THD *thd);
|
int ha_prepare(THD *thd);
|
||||||
|
@ -124,6 +124,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
enum enum_mdl_type {
|
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.
|
An intention exclusive metadata lock (IX). Used only for scoped locks.
|
||||||
Owner of this type of lock can acquire upgradable exclusive locks on
|
Owner of this type of lock can acquire upgradable exclusive locks on
|
||||||
@ -599,12 +601,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
MDL_request& operator=(const MDL_request &)
|
MDL_request& operator=(const MDL_request &)
|
||||||
{
|
{
|
||||||
|
type= MDL_NOT_INITIALIZED;
|
||||||
ticket= NULL;
|
ticket= NULL;
|
||||||
/* Do nothing, in particular, don't try to copy the key. */
|
/* Do nothing, in particular, don't try to copy the key. */
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
/* Another piece of ugliness for TABLE_LIST constructor */
|
/* Another piece of ugliness for TABLE_LIST constructor */
|
||||||
MDL_request() {}
|
MDL_request(): type(MDL_NOT_INITIALIZED), ticket(NULL) {}
|
||||||
|
|
||||||
MDL_request(const MDL_request *rhs)
|
MDL_request(const MDL_request *rhs)
|
||||||
:type(rhs->type),
|
:type(rhs->type),
|
||||||
|
@ -1053,10 +1053,10 @@ handle_rpl_parallel_thread(void *arg)
|
|||||||
server_threads.insert(thd);
|
server_threads.insert(thd);
|
||||||
set_current_thd(thd);
|
set_current_thd(thd);
|
||||||
pthread_detach_this_thread();
|
pthread_detach_this_thread();
|
||||||
|
thd->store_globals();
|
||||||
thd->init_for_queries();
|
thd->init_for_queries();
|
||||||
thd->variables.binlog_annotate_row_events= 0;
|
thd->variables.binlog_annotate_row_events= 0;
|
||||||
init_thr_lock();
|
init_thr_lock();
|
||||||
thd->store_globals();
|
|
||||||
thd->system_thread= SYSTEM_THREAD_SLAVE_SQL;
|
thd->system_thread= SYSTEM_THREAD_SLAVE_SQL;
|
||||||
thd->security_ctx->skip_grants();
|
thd->security_ctx->skip_grants();
|
||||||
thd->variables.max_allowed_packet= slave_max_allowed_packet;
|
thd->variables.max_allowed_packet= slave_max_allowed_packet;
|
||||||
|
@ -1717,6 +1717,10 @@ int vers_insert_history_row(TABLE *table)
|
|||||||
if (row_start->cmp(row_start->ptr, row_end->ptr) >= 0)
|
if (row_start->cmp(row_start->ptr, row_end->ptr) >= 0)
|
||||||
return 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]);
|
return table->file->ha_write_row(table->record[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2017, MariaDB Corporation, Alibaba Corporation
|
Copyright (c) 2017, MariaDB Corporation, Alibaba Corporation
|
||||||
|
Copyrgiht (c) 2020, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
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)
|
if (mdl_lock_used)
|
||||||
thd->mdl_context.release_lock(mdl_request.ticket);
|
thd->mdl_context.release_lock(mdl_request.ticket);
|
||||||
write_unlock(table);
|
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_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT);
|
||||||
}
|
}
|
||||||
DBUG_ASSERT(table->reginfo.lock_type == TL_READ);
|
DBUG_ASSERT(table->reginfo.lock_type == TL_READ);
|
||||||
|
25
sql/table.cc
25
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_start_field()->field_index);
|
||||||
bitmap_set_bit(write_set, vers_end_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;
|
||||||
file->column_bitmaps_signal();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (vers_start_field()->store_timestamp(in_use->query_start(),
|
|
||||||
in_use->query_start_sec_part()))
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (versioned(VERS_TIMESTAMP) &&
|
||||||
|
vers_start_field()->store_timestamp(in_use->query_start(),
|
||||||
|
in_use->query_start_sec_part()))
|
||||||
{
|
{
|
||||||
if (!vers_write)
|
DBUG_ASSERT(0);
|
||||||
{
|
|
||||||
file->column_bitmaps_signal();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vers_end_field()->set_max();
|
vers_end_field()->set_max();
|
||||||
bitmap_set_bit(read_set, vers_end_field()->field_index);
|
bitmap_set_bit(read_set, vers_end_field()->field_index);
|
||||||
file->column_bitmaps_signal();
|
file->column_bitmaps_signal();
|
||||||
|
if (vfield)
|
||||||
|
update_virtual_fields(file, VCOL_UPDATE_FOR_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -689,7 +689,8 @@ bool trans_xa_commit(THD *thd)
|
|||||||
{
|
{
|
||||||
DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
|
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));
|
my_error(ER_XAER_RMERR, MYF(0));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -21150,39 +21150,49 @@ ha_innobase::can_convert_varstring(const Field_varstring* field,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool is_part_of_a_key(const Field_blob *field)
|
||||||
ha_innobase::can_convert_blob(const Field_blob* field,
|
|
||||||
const Column_definition& new_type) const
|
|
||||||
{
|
{
|
||||||
if (new_type.type_handler() != field->type_handler()) {
|
const TABLE_SHARE *s= field->table->s;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!new_type.compression_method() != !field->compression_method()) {
|
for (uint i= 0; i < s->keys; i++)
|
||||||
return false;
|
{
|
||||||
}
|
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()) {
|
bool ha_innobase::can_convert_blob(const Field_blob *field,
|
||||||
Charset field_cs(field->charset());
|
const Column_definition &new_type) const
|
||||||
if (!field_cs.encoding_allows_reinterpret_as(
|
{
|
||||||
new_type.charset)) {
|
if (new_type.type_handler() != field->type_handler())
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!field_cs.eq_collation_specific_names(new_type.charset)) {
|
if (!new_type.compression_method() != !field->compression_method())
|
||||||
bool is_part_of_a_key
|
return false;
|
||||||
= !field->part_of_key.is_clear_all();
|
|
||||||
return !is_part_of_a_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
Compare_keys ha_innobase::compare_key_parts(
|
||||||
@ -21808,3 +21818,70 @@ ib_push_frm_error(
|
|||||||
break;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -163,6 +163,8 @@ row_ins_step(
|
|||||||
#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
|
#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
|
||||||
inserted */
|
inserted */
|
||||||
|
|
||||||
|
struct row_prebuilt_t;
|
||||||
|
|
||||||
/** Insert node structure */
|
/** Insert node structure */
|
||||||
struct ins_node_t
|
struct ins_node_t
|
||||||
{
|
{
|
||||||
@ -203,6 +205,7 @@ struct ins_node_t
|
|||||||
entry_list and sys fields are stored here;
|
entry_list and sys fields are stored here;
|
||||||
if this is NULL, entry list should be created
|
if this is NULL, entry list should be created
|
||||||
and buffers for sys fields in row allocated */
|
and buffers for sys fields in row allocated */
|
||||||
|
void vers_update_end(row_prebuilt_t *prebuilt, bool history_row);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Create an insert object.
|
/** Create an insert object.
|
||||||
|
@ -354,7 +354,32 @@ struct upd_t{
|
|||||||
fields[n_fields++] = field;
|
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. */
|
@return true if modified, false otherwise. */
|
||||||
bool is_modified(uint16_t field_no) const
|
bool is_modified(uint16_t field_no) const
|
||||||
{
|
{
|
||||||
@ -494,25 +519,25 @@ private:
|
|||||||
make_versioned_delete().
|
make_versioned_delete().
|
||||||
@param[in] trx transaction
|
@param[in] trx transaction
|
||||||
@param[in] vers_sys_idx table->row_start or table->row_end */
|
@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:
|
public:
|
||||||
/** Also set row_start = CURRENT_TIMESTAMP/trx->id
|
/** Also set row_start = CURRENT_TIMESTAMP/trx->id
|
||||||
@param[in] trx transaction */
|
@param[in] trx transaction */
|
||||||
void make_versioned_update(const trx_t* trx)
|
void vers_make_update(const trx_t *trx)
|
||||||
{
|
{
|
||||||
make_versioned_helper(trx, table->vers_start);
|
vers_update_fields(trx, table->vers_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Only set row_end = CURRENT_TIMESTAMP/trx->id.
|
/** Only set row_end = CURRENT_TIMESTAMP/trx->id.
|
||||||
Do not touch other fields at all.
|
Do not touch other fields at all.
|
||||||
@param[in] trx transaction */
|
@param[in] trx transaction */
|
||||||
void make_versioned_delete(const trx_t* trx)
|
void vers_make_delete(const trx_t *trx)
|
||||||
{
|
{
|
||||||
update->n_fields = 0;
|
update->n_fields = 0;
|
||||||
is_delete = VERSIONED_DELETE;
|
is_delete = VERSIONED_DELETE;
|
||||||
make_versioned_helper(trx, table->vers_end);
|
vers_update_fields(trx, table->vers_end);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UPD_NODE_MAGIC_N 1579975
|
#define UPD_NODE_MAGIC_N 1579975
|
||||||
|
@ -1331,23 +1331,6 @@ row_mysql_get_table_status(
|
|||||||
return(err);
|
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.
|
/** Does an insert for MySQL.
|
||||||
@param[in] mysql_rec row in the MySQL format
|
@param[in] mysql_rec row in the MySQL format
|
||||||
@param[in,out] prebuilt prebuilt struct in MySQL handle
|
@param[in,out] prebuilt prebuilt struct in MySQL handle
|
||||||
@ -1415,29 +1398,8 @@ row_insert_for_mysql(
|
|||||||
&blob_heap);
|
&blob_heap);
|
||||||
|
|
||||||
if (ins_mode != ROW_INS_NORMAL) {
|
if (ins_mode != ROW_INS_NORMAL) {
|
||||||
#ifndef DBUG_OFF
|
node->vers_update_end(prebuilt, ins_mode == ROW_INS_HISTORICAL);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
savept = trx_savept_take(trx);
|
savept = trx_savept_take(trx);
|
||||||
|
|
||||||
@ -1871,10 +1833,10 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
|
|||||||
|
|
||||||
if (prebuilt->versioned_write) {
|
if (prebuilt->versioned_write) {
|
||||||
if (node->is_delete == VERSIONED_DELETE) {
|
if (node->is_delete == VERSIONED_DELETE) {
|
||||||
node->make_versioned_delete(trx);
|
node->vers_make_delete(trx);
|
||||||
} else if (node->update->affects_versioned()) {
|
} else if (node->update->affects_versioned()) {
|
||||||
node->make_versioned_update(trx);
|
node->vers_make_update(trx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -2230,14 +2192,14 @@ row_update_cascade_for_mysql(
|
|||||||
|
|
||||||
if (table->versioned()) {
|
if (table->versioned()) {
|
||||||
if (node->is_delete == PLAIN_DELETE) {
|
if (node->is_delete == PLAIN_DELETE) {
|
||||||
node->make_versioned_delete(trx);
|
node->vers_make_delete(trx);
|
||||||
} else if (node->update->affects_versioned()) {
|
} else if (node->update->affects_versioned()) {
|
||||||
dberr_t err = row_update_vers_insert(thr, node);
|
dberr_t err = row_update_vers_insert(thr, node);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
node->make_versioned_update(trx);
|
node->vers_make_update(trx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -3173,34 +3173,59 @@ Supposed to be called only by make_versioned_update() and
|
|||||||
make_versioned_delete().
|
make_versioned_delete().
|
||||||
@param[in] trx transaction
|
@param[in] trx transaction
|
||||||
@param[in] vers_sys_idx table->row_start or table->row_end */
|
@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
|
ut_ad(in_mysql_interface); // otherwise needs to recalculate node->cmpl_info
|
||||||
// node->cmpl_info
|
ut_ad(idx == table->vers_start || idx == table->vers_end);
|
||||||
ut_ad(idx == table->vers_start || idx == table->vers_end);
|
|
||||||
|
|
||||||
dict_index_t* clust_index = dict_table_get_first_index(table);
|
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;
|
||||||
|
|
||||||
/* row_create_update_node_for_mysql() pre-allocated this much.
|
for (ulint i= 0; i < update->n_fields; ++i)
|
||||||
At least one PK column always remains unchanged. */
|
{
|
||||||
ut_ad(update->n_fields < ulint(table->n_cols + table->n_v_cols));
|
if (update->fields[i].field_no == field_no)
|
||||||
|
{
|
||||||
|
ufield= &update->fields[i];
|
||||||
|
goto skip_append;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
update->n_fields++;
|
/* row_create_update_node_for_mysql() pre-allocated this much.
|
||||||
upd_field_t* ufield = upd_get_nth_field(update, update->n_fields - 1);
|
At least one PK column always remains unchanged. */
|
||||||
const dict_col_t* col = dict_table_get_nth_col(table, idx);
|
ut_ad(update->n_fields < ulint(table->n_cols + table->n_v_cols));
|
||||||
|
|
||||||
upd_field_set_field_no(ufield, static_cast<uint16_t>(
|
update->n_fields++;
|
||||||
dict_col_get_clust_pos(
|
ufield= upd_get_nth_field(update, update->n_fields - 1);
|
||||||
col, clust_index)),
|
upd_field_set_field_no(ufield, static_cast<uint16_t>(field_no), clust_index);
|
||||||
clust_index);
|
|
||||||
|
|
||||||
char* where = reinterpret_cast<char*>(update->vers_sys_value);
|
skip_append:
|
||||||
if (col->vers_native()) {
|
char *where= reinterpret_cast<char *>(update->vers_sys_value);
|
||||||
mach_write_to_8(where, trx->id);
|
if (col->vers_native())
|
||||||
} else {
|
mach_write_to_8(where, trx->id);
|
||||||
thd_get_query_start_data(trx->mysql_thd, where);
|
else
|
||||||
}
|
thd_get_query_start_data(trx->mysql_thd, where);
|
||||||
|
|
||||||
dfield_set_data(&ufield->new_val, update->vers_sys_value, col->len);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1272,7 +1272,8 @@ trx_update_mod_tables_timestamp(
|
|||||||
dict_table_t* table = it->first;
|
dict_table_t* table = it->first;
|
||||||
table->update_time = now;
|
table->update_time = now;
|
||||||
#ifdef UNIV_DEBUG
|
#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
|
/* do not evict when committing DDL operations
|
||||||
or if some other transaction is holding the
|
or if some other transaction is holding the
|
||||||
table handle */
|
table handle */
|
||||||
@ -1281,7 +1282,11 @@ trx_update_mod_tables_timestamp(
|
|||||||
/* recheck while holding the mutex that blocks
|
/* recheck while holding the mutex that blocks
|
||||||
table->acquire() */
|
table->acquire() */
|
||||||
mutex_enter(&dict_sys.mutex);
|
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);
|
dict_sys.remove(table, true);
|
||||||
}
|
}
|
||||||
mutex_exit(&dict_sys.mutex);
|
mutex_exit(&dict_sys.mutex);
|
||||||
|
@ -2947,6 +2947,10 @@ static void reset_thd_trn(THD *thd, MARIA_HA *first_table)
|
|||||||
DBUG_VOID_RETURN;
|
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
|
Performs an implicit commit of the Maria transaction and creates a new
|
||||||
|
@ -158,6 +158,7 @@ public:
|
|||||||
{
|
{
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
static bool has_active_transaction(THD *thd);
|
||||||
static int implicit_commit(THD *thd, bool new_trn);
|
static int implicit_commit(THD *thd, bool new_trn);
|
||||||
/**
|
/**
|
||||||
* Multi Range Read interface
|
* Multi Range Read interface
|
||||||
|
Loading…
x
Reference in New Issue
Block a user