Commit 1bd22ab3 authored by jan's avatar jan

Setting a isolation level of the transaction to read committed

weakens the locks for this session similarly like the option
innodb_locks_unsafe_for_binlog. This patch removes almost all
gap locking (used in next-key locking) and makes MySQL to release
the row locks on the rows which does not belong to result set.
Additionally, nonlocking selects on INSERT INTO SELECT,
UPDATE ... (SELECT ...), and CREATE ... SELECT ... use a
nonlocking consistent read. If a binlog is used, then binlog
format should be set to row based binloging to make the execution
of the complex SQL statements.
parent f58fa91c
......@@ -3875,7 +3875,8 @@ ha_innobase::unlock_row(void)
switch (prebuilt->row_read_type) {
case ROW_READ_WITH_LOCKS:
if (!srv_locks_unsafe_for_binlog) {
if (!srv_locks_unsafe_for_binlog
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED) {
break;
}
/* fall through */
......@@ -3907,7 +3908,13 @@ ha_innobase::try_semi_consistent_read(bool yes)
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
if (yes && srv_locks_unsafe_for_binlog) {
/* Row read type is set to semi consistent read if this was
requested by the MySQL and either innodb_locks_unsafe_for_binlog
option is used or this session is using READ COMMITTED isolation
level. */
if (yes && (srv_locks_unsafe_for_binlog
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
} else {
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
......@@ -6390,12 +6397,6 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use++;
prebuilt->mysql_has_locked = TRUE;
if (trx->n_mysql_tables_in_use == 1) {
trx->isolation_level = innobase_map_isolation_level(
(enum_tx_isolation)
thd->variables.tx_isolation);
}
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
&& prebuilt->select_lock_type == LOCK_NONE
&& (thd->options
......@@ -6869,11 +6870,22 @@ ha_innobase::store_lock(
TL_IGNORE */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
trx_t* trx = prebuilt->trx;
/* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
Be careful to ignore TL_IGNORE if we are going to do something with
only 'real' locks! */
/* If no MySQL tables is use we need to set isolation level
of the transaction. */
if (lock_type != TL_IGNORE
&& trx->n_mysql_tables_in_use == 0) {
trx->isolation_level = innobase_map_isolation_level(
(enum_tx_isolation)
thd->variables.tx_isolation);
}
if ((lock_type == TL_READ && thd->in_lock_tables) ||
(lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) ||
lock_type == TL_READ_WITH_SHARED_LOCKS ||
......@@ -6898,15 +6910,21 @@ ha_innobase::store_lock(
unexpected if an obsolete consistent read view would be
used. */
if (srv_locks_unsafe_for_binlog
&& prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE
ulint isolation_level;
isolation_level = trx->isolation_level;
if ((srv_locks_unsafe_for_binlog
|| isolation_level == TRX_ISO_READ_COMMITTED)
&& isolation_level != TRX_ISO_SERIALIZABLE
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
&& (thd->lex->sql_command == SQLCOM_INSERT_SELECT
|| thd->lex->sql_command == SQLCOM_UPDATE
|| thd->lex->sql_command == SQLCOM_CREATE_TABLE)) {
/* In case we have innobase_locks_unsafe_for_binlog
option set and isolation level of the transaction
/* If we either have innobase_locks_unsafe_for_binlog
option set or this session is using READ COMMITTED
isolation level and isolation level of the transaction
is not set to serializable and MySQL is doing
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
CREATE ... SELECT... without FOR UPDATE or
......
......@@ -244,7 +244,8 @@ row_update_for_mysql(
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
handle */
/*************************************************************************
This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
session is using a READ COMMITTED isolation level. Before
calling this function we must use trx_reset_new_rec_lock_info() and
trx_register_new_rec_lock() to store the information which new record locks
really were set. This function removes a newly set lock under prebuilt->pcur,
......
......@@ -544,7 +544,9 @@ struct trx_struct{
the transaction; note that it is also
in the lock list trx_locks */
dict_index_t* new_rec_locks[2];/* these are normally NULL; if
srv_locks_unsafe_for_binlog is TRUE,
srv_locks_unsafe_for_binlog is TRUE
or session is using READ COMMITTED
isolation level,
in a cursor search, if we set a new
record lock on an index, this is set
to point to the index; this is
......
......@@ -2001,7 +2001,8 @@ lock_rec_lock_fast(
if (!impl) {
lock_rec_create(mode, rec, index, trx);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
trx_register_new_rec_lock(trx, index);
}
}
......@@ -2027,7 +2028,8 @@ lock_rec_lock_fast(
if (!lock_rec_get_nth_bit(lock, heap_no)) {
lock_rec_set_nth_bit(lock, heap_no);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
trx_register_new_rec_lock(trx, index);
}
}
......@@ -2087,7 +2089,8 @@ lock_rec_lock_slow(
err = lock_rec_enqueue_waiting(mode, rec, index, thr);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
trx_register_new_rec_lock(trx, index);
}
} else {
......@@ -2096,7 +2099,8 @@ lock_rec_lock_slow(
lock_rec_add_to_queue(LOCK_REC | mode, rec, index,
trx);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
trx_register_new_rec_lock(trx, index);
}
}
......@@ -2436,14 +2440,17 @@ lock_rec_inherit_to_gap(
lock = lock_rec_get_first(rec);
/* If srv_locks_unsafe_for_binlog is TRUE, we do not want locks set
/* If srv_locks_unsafe_for_binlog is TRUE or session is using
READ COMMITTED isolation level, we do not want locks set
by an UPDATE or a DELETE to be inherited as gap type locks. But we
DO want S-locks set by a consistency constraint to be inherited also
then. */
while (lock != NULL) {
if (!lock_rec_get_insert_intention(lock)
&& !(srv_locks_unsafe_for_binlog
&& !((srv_locks_unsafe_for_binlog
|| lock->trx->isolation_level ==
TRX_ISO_READ_COMMITTED)
&& lock_get_mode(lock) == LOCK_X)) {
lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock)
......
--binlog_cache_size=32768
--binlog_cache_size=32768 --innodb_lock_wait_timeout=5 --loose_innodb_lock_wait_timeout=5
......@@ -3214,3 +3214,260 @@ UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu';
ERROR 23000: Upholding foreign key constraints for table 't1', entry 'other-somevalu', key 1 would lead to a duplicate entry
DROP TABLE t2;
DROP TABLE t1;
create table t1 (id int not null, f_id int not null, f int not null,
primary key(f_id, id)) engine=innodb;
create table t2 (id int not null,s_id int not null,s varchar(200),
primary key(id)) engine=innodb;
INSERT INTO t1 VALUES (8, 1, 3);
INSERT INTO t1 VALUES (1, 2, 1);
INSERT INTO t2 VALUES (1, 0, '');
INSERT INTO t2 VALUES (8, 1, '');
commit;
DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
WHERE mm.id IS NULL;
select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id)
where mm.id is null lock in share mode;
id f_id f
drop table t1,t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t1 set b = 5 where b = 1;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
select * from t1 where a = 7 and b = 3 for update;
a b
7 3
commit;
commit;
drop table t1;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
commit;
set autocommit = 0;
select * from t1 lock in share mode;
a b
1 1
2 2
3 1
4 2
5 1
6 2
update t1 set b = 5 where b = 1;
set autocommit = 0;
select * from t1 where a = 2 and b = 2 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
select * from t1 where b = 1 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
insert into t1 select * from t2;
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t1 set b = (select e from t2 where a = d);
commit;
commit;
drop table t1, t2;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
create table t1(a int not null, b int, primary key(a)) engine=innodb
select * from t2;
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
insert into t1 select * from t2;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
update t1 set b = (select e from t2 where a = d);
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
create table t1(a int not null, b int, primary key(a)) engine=innodb
select * from t2;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
insert into t1 select * from t2 lock in share mode;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t1 set b = (select e from t2 where a = d lock in share mode);
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
create table t1(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
insert into t1 select * from t2 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t1 set b = (select e from t2 where a = d for update);
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
create table t1(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t2;
This diff is collapsed.
--innodb_locks_unsafe_for_binlog=true
--innodb_locks_unsafe_for_binlog=true --innodb_lock_wait_timeout=2 --loose_innodb_lock_wait_timeout=2
\ No newline at end of file
......@@ -15,7 +15,7 @@ where mm.id is null lock in share mode;
id f_id f
drop table t1,t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
select * from t1 lock in share mode;
......@@ -26,6 +26,7 @@ a b
4 2
5 1
6 2
7 3
update t1 set b = 5 where b = 1;
set autocommit = 0;
select * from t1 where a = 2 and b = 2 for update;
......@@ -33,3 +34,213 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
update t1 set b = 5 where b = 1;
set autocommit = 0;
select * from t1 where a = 7 and b = 3 for update;
a b
7 3
commit;
commit;
drop table t1;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
insert into t1 select * from t2;
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
1 6
4 1
5 1
set autocommit = 0;
update t1 set b = (select e from t2 where a = d);
commit;
commit;
drop table t1, t2;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
1 6
4 1
5 1
set autocommit = 0;
create table t1(a int not null, b int, primary key(a)) engine=innodb
select * from t2;
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
insert into t1 select * from t2;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
update t1 set b = (select e from t2 where a = d);
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
1 6
4 1
5 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
create table t1(a int not null, b int, primary key(a)) engine=innodb
select * from t2;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
insert into t1 select * from t2 lock in share mode;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
1 6
4 1
5 1
set autocommit = 0;
update t1 set b = (select e from t2 where a = d lock in share mode);
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
1 6
4 1
5 1
set autocommit = 0;
create table t1(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
insert into t1 select * from t2 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
1 6
4 1
5 1
set autocommit = 0;
update t1 set b = (select e from t2 where a = d for update);
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1, t2;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
1 6
4 1
5 1
set autocommit = 0;
create table t1(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t2;
-- source include/have_innodb.inc
#
# Note that these tests uses a innodb_locks_unsafe_for_binlog option.
#
# Note that these tests uses options
# innodb_locks_unsafe_for_binlog = true
# innodb_lock_timeout = 5
#
# Test cases for a bug #15650
#
......@@ -33,7 +35,7 @@ connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
select * from t1 lock in share mode;
......@@ -50,6 +52,348 @@ commit;
connection b;
commit;
drop table t1;
connection default;
disconnect a;
disconnect b;
#
# unlock row test
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
update t1 set b = 5 where b = 1;
connection b;
set autocommit = 0;
#
# X-lock to record (7,3) should be released in a update
#
select * from t1 where a = 7 and b = 3 for update;
commit;
connection a;
commit;
drop table t1;
connection default;
disconnect a;
disconnect b;
#
# Consistent read should be used in following selects
#
# 1) INSERT INTO ... SELECT
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
insert into t1 select * from t2;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# 2) UPDATE ... = ( SELECT ...)
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
update t1 set b = (select e from t2 where a = d);
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# 3) CREATE ... SELECT
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
create table t1(a int not null, b int, primary key(a)) engine=innodb
select * from t2;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# Consistent read should not be used if isolation level is serializable
#
# 1) INSERT INTO ... SELECT
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--error 1205
insert into t1 select * from t2;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# 2) UPDATE ... = ( SELECT ...)
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--error 1205
update t1 set b = (select e from t2 where a = d);
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# 3) CREATE ... SELECT
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--error 1205
create table t1(a int not null, b int, primary key(a)) engine=innodb
select * from t2;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t2;
#
# Consistent read should not be used if locking read is used case
# (a) lock in share mode
#
# 1) INSERT INTO ... SELECT
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
--error 1205
insert into t1 select * from t2 lock in share mode;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# 2) UPDATE ... = ( SELECT ...)
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
--error 1205
update t1 set b = (select e from t2 where a = d lock in share mode);
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# 3) CREATE ... SELECT
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
--error 1205
create table t1(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t2;
#
# Consistent read should not be used if locking read is used case
# (b) for update
#
# 1) INSERT INTO ... SELECT
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
--error 1205
insert into t1 select * from t2 for update;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# 2) UPDATE ... = ( SELECT ...)
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
--error 1205
update t1 set b = (select e from t2 where a = d for update);
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2;
#
# 3) CREATE ... SELECT
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (1,6),(5,1),(4,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
--error 1205
create table t1(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t2;
......@@ -1435,7 +1435,8 @@ run_again:
}
/*************************************************************************
This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
this session is using a READ COMMITTED isolation level. Before
calling this function we must use trx_reset_new_rec_lock_info() and
trx_register_new_rec_lock() to store the information which new record locks
really were set. This function removes a newly set lock under prebuilt->pcur,
......@@ -1466,11 +1467,13 @@ row_unlock_for_mysql(
ut_ad(prebuilt && trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (!srv_locks_unsafe_for_binlog) {
if (!(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
fprintf(stderr,
"InnoDB: Error: calling row_unlock_for_mysql though\n"
"InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n");
"InnoDB: srv_locks_unsafe_for_binlog is FALSE and\n"
"InnoDB: this session is not using READ COMMITTED isolation level.\n");
return(DB_SUCCESS);
}
......
......@@ -710,12 +710,17 @@ row_sel_get_clust_rec(
if (!node->read_view) {
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using READ COMMITTED isolation level
we lock only the record, i.e., next-key locking is
not used. */
ulint lock_type;
trx_t* trx;
trx = thr_get_trx(thr);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
lock_type = LOCK_REC_NOT_GAP;
} else {
lock_type = LOCK_ORDINARY;
......@@ -1307,16 +1312,22 @@ rec_loop:
if (!consistent_read) {
/* If innodb_locks_unsafe_for_binlog option is used,
we lock only the record, i.e., next-key locking is
not used. */
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using READ COMMITTED isolation
level, we lock only the record, i.e., next-key
locking is not used. */
rec_t* next_rec = page_rec_get_next(rec);
ulint lock_type;
trx_t* trx;
trx = thr_get_trx(thr);
offsets = rec_get_offsets(next_rec, index, offsets,
ULINT_UNDEFINED, &heap);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
lock_type = LOCK_REC_NOT_GAP;
} else {
lock_type = LOCK_ORDINARY;
......@@ -1350,15 +1361,21 @@ rec_loop:
if (!consistent_read) {
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using READ COMMITTED isolation level,
we lock only the record, i.e., next-key locking is
not used. */
ulint lock_type;
trx_t* trx;
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
if (srv_locks_unsafe_for_binlog) {
trx = thr_get_trx(thr);
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
lock_type = LOCK_REC_NOT_GAP;
} else {
lock_type = LOCK_ORDINARY;
......@@ -3206,10 +3223,12 @@ stderr);
}
/* Reset the new record lock info if srv_locks_unsafe_for_binlog
is set. Then we are able to remove the record locks set here on an
individual row. */
is set or session is using a READ COMMITED isolation level. Then
we are able to remove the record locks set here on an individual
row. */
if (srv_locks_unsafe_for_binlog
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
trx_reset_new_rec_lock_info(trx);
......@@ -3578,13 +3597,15 @@ rec_loop:
if (page_rec_is_supremum(rec)) {
if (set_also_gap_locks
&& !srv_locks_unsafe_for_binlog
&& !(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
we do not lock gaps. Supremum record is really
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using a READ COMMITTED isolation
level we do not lock gaps. Supremum record is really
a gap and therefore we do not set locks there. */
offsets = rec_get_offsets(rec, index, offsets,
......@@ -3704,12 +3725,14 @@ wrong_offs:
if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
if (set_also_gap_locks
&& !srv_locks_unsafe_for_binlog
&& !(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a gap lock on the index
record only if innodb_locks_unsafe_for_binlog
option is not set */
option is not set or this session is not
using a READ COMMITTED isolation level. */
err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type,
......@@ -3735,12 +3758,14 @@ wrong_offs:
if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
if (set_also_gap_locks
&& !srv_locks_unsafe_for_binlog
&& !(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a gap lock on the index
record only if innodb_locks_unsafe_for_binlog
option is not set */
option is not set or this session is not
using a READ COMMITTED isolation level. */
err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type,
......@@ -3771,16 +3796,18 @@ wrong_offs:
is a non-delete marked record, then it is enough to lock its
existence with LOCK_REC_NOT_GAP. */
/* If innodb_locks_unsafe_for_binlog option is used,
we lock only the record, i.e., next-key locking is
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using a READ COMMITED isolation
level we lock only the record, i.e., next-key locking is
not used. */
ulint lock_type;
if (!set_also_gap_locks
|| srv_locks_unsafe_for_binlog
|| (unique_search && !UNIV_UNLIKELY(
rec_get_deleted_flag(rec, comp)))) {
|| trx->isolation_level == TRX_ISO_READ_COMMITTED
|| (unique_search
&& !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) {
goto no_gap_lock;
} else {
......@@ -3939,7 +3966,8 @@ no_gap_lock:
/* The record is delete-marked: we can skip it */
if (srv_locks_unsafe_for_binlog
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE
&& !did_semi_consistent_read) {
......@@ -3992,7 +4020,8 @@ requires_clust_rec:
/* The record is delete marked: we can skip it */
if (srv_locks_unsafe_for_binlog
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* No need to keep a lock on a delete-marked
......@@ -4113,7 +4142,8 @@ next_rec:
}
did_semi_consistent_read = FALSE;
if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog)
if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
trx_reset_new_rec_lock_info(trx);
......@@ -4202,7 +4232,11 @@ lock_wait_or_error:
sel_restore_position_for_mysql(&same_user_rec,
BTR_SEARCH_LEAF, pcur,
moves_up, &mtr);
if (srv_locks_unsafe_for_binlog && !same_user_rec) {
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& !same_user_rec) {
/* Since we were not able to restore the cursor
on the same user record, we cannot use
row_unlock_for_mysql() to unlock any records, and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment