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) ...@@ -3875,7 +3875,8 @@ ha_innobase::unlock_row(void)
switch (prebuilt->row_read_type) { switch (prebuilt->row_read_type) {
case ROW_READ_WITH_LOCKS: 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; break;
} }
/* fall through */ /* fall through */
...@@ -3907,7 +3908,13 @@ ha_innobase::try_semi_consistent_read(bool yes) ...@@ -3907,7 +3908,13 @@ ha_innobase::try_semi_consistent_read(bool yes)
{ {
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; 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; prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
} else { } else {
prebuilt->row_read_type = ROW_READ_WITH_LOCKS; prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
...@@ -6390,12 +6397,6 @@ ha_innobase::external_lock( ...@@ -6390,12 +6397,6 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use++; trx->n_mysql_tables_in_use++;
prebuilt->mysql_has_locked = TRUE; 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 if (trx->isolation_level == TRX_ISO_SERIALIZABLE
&& prebuilt->select_lock_type == LOCK_NONE && prebuilt->select_lock_type == LOCK_NONE
&& (thd->options && (thd->options
...@@ -6869,11 +6870,22 @@ ha_innobase::store_lock( ...@@ -6869,11 +6870,22 @@ ha_innobase::store_lock(
TL_IGNORE */ TL_IGNORE */
{ {
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; 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! /* 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 Be careful to ignore TL_IGNORE if we are going to do something with
only 'real' locks! */ 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) || if ((lock_type == TL_READ && thd->in_lock_tables) ||
(lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) || (lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) ||
lock_type == TL_READ_WITH_SHARED_LOCKS || lock_type == TL_READ_WITH_SHARED_LOCKS ||
...@@ -6898,15 +6910,21 @@ ha_innobase::store_lock( ...@@ -6898,15 +6910,21 @@ ha_innobase::store_lock(
unexpected if an obsolete consistent read view would be unexpected if an obsolete consistent read view would be
used. */ used. */
if (srv_locks_unsafe_for_binlog ulint isolation_level;
&& prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE
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) && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
&& (thd->lex->sql_command == SQLCOM_INSERT_SELECT && (thd->lex->sql_command == SQLCOM_INSERT_SELECT
|| thd->lex->sql_command == SQLCOM_UPDATE || thd->lex->sql_command == SQLCOM_UPDATE
|| thd->lex->sql_command == SQLCOM_CREATE_TABLE)) { || thd->lex->sql_command == SQLCOM_CREATE_TABLE)) {
/* In case we have innobase_locks_unsafe_for_binlog /* If we either have innobase_locks_unsafe_for_binlog
option set and isolation level of the transaction 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 is not set to serializable and MySQL is doing
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
CREATE ... SELECT... without FOR UPDATE or CREATE ... SELECT... without FOR UPDATE or
......
...@@ -244,7 +244,8 @@ row_update_for_mysql( ...@@ -244,7 +244,8 @@ row_update_for_mysql(
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
handle */ 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 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 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, really were set. This function removes a newly set lock under prebuilt->pcur,
......
...@@ -544,7 +544,9 @@ struct trx_struct{ ...@@ -544,7 +544,9 @@ struct trx_struct{
the transaction; note that it is also the transaction; note that it is also
in the lock list trx_locks */ in the lock list trx_locks */
dict_index_t* new_rec_locks[2];/* these are normally NULL; if 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 in a cursor search, if we set a new
record lock on an index, this is set record lock on an index, this is set
to point to the index; this is to point to the index; this is
......
...@@ -2001,7 +2001,8 @@ lock_rec_lock_fast( ...@@ -2001,7 +2001,8 @@ lock_rec_lock_fast(
if (!impl) { if (!impl) {
lock_rec_create(mode, rec, index, trx); 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); trx_register_new_rec_lock(trx, index);
} }
} }
...@@ -2027,7 +2028,8 @@ lock_rec_lock_fast( ...@@ -2027,7 +2028,8 @@ lock_rec_lock_fast(
if (!lock_rec_get_nth_bit(lock, heap_no)) { if (!lock_rec_get_nth_bit(lock, heap_no)) {
lock_rec_set_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); trx_register_new_rec_lock(trx, index);
} }
} }
...@@ -2087,7 +2089,8 @@ lock_rec_lock_slow( ...@@ -2087,7 +2089,8 @@ lock_rec_lock_slow(
err = lock_rec_enqueue_waiting(mode, rec, index, thr); 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); trx_register_new_rec_lock(trx, index);
} }
} else { } else {
...@@ -2096,7 +2099,8 @@ lock_rec_lock_slow( ...@@ -2096,7 +2099,8 @@ lock_rec_lock_slow(
lock_rec_add_to_queue(LOCK_REC | mode, rec, index, lock_rec_add_to_queue(LOCK_REC | mode, rec, index,
trx); 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); trx_register_new_rec_lock(trx, index);
} }
} }
...@@ -2436,14 +2440,17 @@ lock_rec_inherit_to_gap( ...@@ -2436,14 +2440,17 @@ lock_rec_inherit_to_gap(
lock = lock_rec_get_first(rec); 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 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 DO want S-locks set by a consistency constraint to be inherited also
then. */ then. */
while (lock != NULL) { while (lock != NULL) {
if (!lock_rec_get_insert_intention(lock) 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_get_mode(lock) == LOCK_X)) {
lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock) 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'; ...@@ -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 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 t2;
DROP TABLE t1; 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;
...@@ -2113,3 +2113,407 @@ UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu'; ...@@ -2113,3 +2113,407 @@ UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu';
DROP TABLE t2; DROP TABLE t2;
DROP TABLE t1; 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;
drop table t1,t2;
#
# Test case where X-locks on unused rows should be released in a
# update (because READ COMMITTED isolation level)
#
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;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t1 set b = 5 where b = 1;
connection b;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
#
# X-lock to record (7,3) should be released in a update
#
select * from t1 where a = 7 and b = 3 for update;
connection a;
commit;
connection b;
commit;
drop table t1;
connection default;
disconnect a;
disconnect b;
#
# Test case where no locks should be released (because we are not
# using READ COMMITTED isolation level)
#
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);
commit;
set autocommit = 0;
select * from t1 lock in share mode;
update t1 set b = 5 where b = 1;
connection b;
set autocommit = 0;
#
# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update
#
--error 1205
select * from t1 where a = 2 and b = 2 for update;
#
# X-lock to record (1,1),(3,1),(5,1) should not be released in a update
#
--error 1205
select * from t1 where b = 1 for update;
connection a;
commit;
connection b;
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;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
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 READ COMMITTED;
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 READ COMMITTED;
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;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--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;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--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;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--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;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--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;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--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;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--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;
--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; ...@@ -15,7 +15,7 @@ where mm.id is null lock in share mode;
id f_id f id f_id f
drop table t1,t2; drop table t1,t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb; 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; commit;
set autocommit = 0; set autocommit = 0;
select * from t1 lock in share mode; select * from t1 lock in share mode;
...@@ -26,6 +26,7 @@ a b ...@@ -26,6 +26,7 @@ a b
4 2 4 2
5 1 5 1
6 2 6 2
7 3
update t1 set b = 5 where b = 1; update t1 set b = 5 where b = 1;
set autocommit = 0; set autocommit = 0;
select * from t1 where a = 2 and b = 2 for update; select * from t1 where a = 2 and b = 2 for update;
...@@ -33,3 +34,213 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction ...@@ -33,3 +34,213 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit; commit;
commit; commit;
drop table t1; 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 -- 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 # Test cases for a bug #15650
# #
...@@ -33,7 +35,7 @@ connect (a,localhost,root,,); ...@@ -33,7 +35,7 @@ connect (a,localhost,root,,);
connect (b,localhost,root,,); connect (b,localhost,root,,);
connection a; connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb; 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; commit;
set autocommit = 0; set autocommit = 0;
select * from t1 lock in share mode; select * from t1 lock in share mode;
...@@ -50,6 +52,348 @@ commit; ...@@ -50,6 +52,348 @@ commit;
connection b; connection b;
commit; commit;
drop table t1; 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 a;
disconnect b; 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: ...@@ -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 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 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, really were set. This function removes a newly set lock under prebuilt->pcur,
...@@ -1466,11 +1467,13 @@ row_unlock_for_mysql( ...@@ -1466,11 +1467,13 @@ row_unlock_for_mysql(
ut_ad(prebuilt && trx); ut_ad(prebuilt && trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); 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, fprintf(stderr,
"InnoDB: Error: calling row_unlock_for_mysql though\n" "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); return(DB_SUCCESS);
} }
......
...@@ -710,12 +710,17 @@ row_sel_get_clust_rec( ...@@ -710,12 +710,17 @@ row_sel_get_clust_rec(
if (!node->read_view) { if (!node->read_view) {
/* Try to place a lock on the index record */ /* 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 we lock only the record, i.e., next-key locking is
not used. */ not used. */
ulint lock_type; 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; lock_type = LOCK_REC_NOT_GAP;
} else { } else {
lock_type = LOCK_ORDINARY; lock_type = LOCK_ORDINARY;
...@@ -1307,16 +1312,22 @@ rec_loop: ...@@ -1307,16 +1312,22 @@ rec_loop:
if (!consistent_read) { if (!consistent_read) {
/* If innodb_locks_unsafe_for_binlog option is used, /* If innodb_locks_unsafe_for_binlog option is used
we lock only the record, i.e., next-key locking is or this session is using READ COMMITTED isolation
not used. */ level, we lock only the record, i.e., next-key
locking is not used. */
rec_t* next_rec = page_rec_get_next(rec); rec_t* next_rec = page_rec_get_next(rec);
ulint lock_type; ulint lock_type;
trx_t* trx;
trx = thr_get_trx(thr);
offsets = rec_get_offsets(next_rec, index, offsets, offsets = rec_get_offsets(next_rec, index, offsets,
ULINT_UNDEFINED, &heap); 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; lock_type = LOCK_REC_NOT_GAP;
} else { } else {
lock_type = LOCK_ORDINARY; lock_type = LOCK_ORDINARY;
...@@ -1350,15 +1361,21 @@ rec_loop: ...@@ -1350,15 +1361,21 @@ rec_loop:
if (!consistent_read) { if (!consistent_read) {
/* Try to place a lock on the index record */ /* 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 we lock only the record, i.e., next-key locking is
not used. */ not used. */
ulint lock_type; ulint lock_type;
trx_t* trx;
offsets = rec_get_offsets(rec, index, offsets, offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap); 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; lock_type = LOCK_REC_NOT_GAP;
} else { } else {
lock_type = LOCK_ORDINARY; lock_type = LOCK_ORDINARY;
...@@ -3206,10 +3223,12 @@ stderr); ...@@ -3206,10 +3223,12 @@ stderr);
} }
/* Reset the new record lock info if srv_locks_unsafe_for_binlog /* 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 is set or session is using a READ COMMITED isolation level. Then
individual row. */ 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) { && prebuilt->select_lock_type != LOCK_NONE) {
trx_reset_new_rec_lock_info(trx); trx_reset_new_rec_lock_info(trx);
...@@ -3578,13 +3597,15 @@ rec_loop: ...@@ -3578,13 +3597,15 @@ rec_loop:
if (page_rec_is_supremum(rec)) { if (page_rec_is_supremum(rec)) {
if (set_also_gap_locks 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) { && prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a lock on the index record */ /* 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
we do not lock gaps. Supremum record is really 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. */ a gap and therefore we do not set locks there. */
offsets = rec_get_offsets(rec, index, offsets, offsets = rec_get_offsets(rec, index, offsets,
...@@ -3704,12 +3725,14 @@ wrong_offs: ...@@ -3704,12 +3725,14 @@ wrong_offs:
if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) { if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
if (set_also_gap_locks 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) { && prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a gap lock on the index /* Try to place a gap lock on the index
record only if innodb_locks_unsafe_for_binlog 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, err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type, prebuilt->select_lock_type,
...@@ -3735,12 +3758,14 @@ wrong_offs: ...@@ -3735,12 +3758,14 @@ wrong_offs:
if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) { if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
if (set_also_gap_locks 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) { && prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a gap lock on the index /* Try to place a gap lock on the index
record only if innodb_locks_unsafe_for_binlog 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, err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type, prebuilt->select_lock_type,
...@@ -3771,16 +3796,18 @@ wrong_offs: ...@@ -3771,16 +3796,18 @@ wrong_offs:
is a non-delete marked record, then it is enough to lock its is a non-delete marked record, then it is enough to lock its
existence with LOCK_REC_NOT_GAP. */ existence with LOCK_REC_NOT_GAP. */
/* If innodb_locks_unsafe_for_binlog option is used, /* If innodb_locks_unsafe_for_binlog option is used
we lock only the record, i.e., next-key locking is or this session is using a READ COMMITED isolation
level we lock only the record, i.e., next-key locking is
not used. */ not used. */
ulint lock_type; ulint lock_type;
if (!set_also_gap_locks if (!set_also_gap_locks
|| srv_locks_unsafe_for_binlog || srv_locks_unsafe_for_binlog
|| (unique_search && !UNIV_UNLIKELY( || trx->isolation_level == TRX_ISO_READ_COMMITTED
rec_get_deleted_flag(rec, comp)))) { || (unique_search
&& !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) {
goto no_gap_lock; goto no_gap_lock;
} else { } else {
...@@ -3939,7 +3966,8 @@ no_gap_lock: ...@@ -3939,7 +3966,8 @@ no_gap_lock:
/* The record is delete-marked: we can skip it */ /* 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 && prebuilt->select_lock_type != LOCK_NONE
&& !did_semi_consistent_read) { && !did_semi_consistent_read) {
...@@ -3992,7 +4020,8 @@ requires_clust_rec: ...@@ -3992,7 +4020,8 @@ requires_clust_rec:
/* The record is delete marked: we can skip it */ /* 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) { && prebuilt->select_lock_type != LOCK_NONE) {
/* No need to keep a lock on a delete-marked /* No need to keep a lock on a delete-marked
...@@ -4113,7 +4142,8 @@ next_rec: ...@@ -4113,7 +4142,8 @@ next_rec:
} }
did_semi_consistent_read = FALSE; 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) { && prebuilt->select_lock_type != LOCK_NONE) {
trx_reset_new_rec_lock_info(trx); trx_reset_new_rec_lock_info(trx);
...@@ -4202,7 +4232,11 @@ lock_wait_or_error: ...@@ -4202,7 +4232,11 @@ lock_wait_or_error:
sel_restore_position_for_mysql(&same_user_rec, sel_restore_position_for_mysql(&same_user_rec,
BTR_SEARCH_LEAF, pcur, BTR_SEARCH_LEAF, pcur,
moves_up, &mtr); 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 /* Since we were not able to restore the cursor
on the same user record, we cannot use on the same user record, we cannot use
row_unlock_for_mysql() to unlock any records, and 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