Fixed bug #31310.

Locked rows of the InnoDB storage was silently skipped in the read-committed
isolation level.

QUICK_RANGE_SELECT for unique ranges lacks second (blocking) read
of the record that was read semi-consistently and just skip it.

The handler::read_multi_range_next method has been modified
to retry previous unique range if the previous read was
semi-consistent.
parent 5df890e5
......@@ -29,6 +29,7 @@ eval SET SESSION STORAGE_ENGINE = $engine_type;
--disable_warnings
drop table if exists t1,t2,t3,t1m,t1i,t2m,t2i,t4;
drop procedure if exists p1;
--enable_warnings
......@@ -1146,4 +1147,128 @@ select @b:=f2 from t1;
select if(@a=@b,"ok","wrong");
drop table t1;
#
# Bug #31310: Locked rows silently skipped in read-committed isolation level.
#
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
SET SESSION AUTOCOMMIT = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--echo # Switch to connection con1
connection con1;
eval
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(256))
ENGINE = $engine_type;
INSERT INTO t1 VALUES (1,2);
--#echo 1. test for locking:
BEGIN;
--enable_info
UPDATE t1 SET b = 12 WHERE a = 1;
--disable_info
SELECT * FROM t1;
--echo # Switch to connection con2
connection con2;
--enable_info
--disable_abort_on_error
--error ER_LOCK_WAIT_TIMEOUT
UPDATE t1 SET b = 21 WHERE a = 1;
--disable_info
--echo # Switch to connection con1
connection con1;
SELECT * FROM t1;
ROLLBACK;
--echo # 2. test for serialized update:
CREATE TABLE t2 (a INT);
TRUNCATE t1;
INSERT INTO t1 VALUES (1,'init');
DELIMITER |;
CREATE PROCEDURE p1()
BEGIN
UPDATE t1 SET b = CONCAT(b, '+con2') WHERE a = 1;
INSERT INTO t2 VALUES ();
END|
DELIMITER ;|
BEGIN;
--enable_info
UPDATE t1 SET b = CONCAT(b, '+con1') WHERE a = 1;
--disable_info
SELECT * FROM t1;
--echo # Switch to connection con2
connection con2;
--send CALL p1;
--echo # Switch to connection con1
connection con1;
SELECT * FROM t1;
COMMIT;
let $bug31310 = 1;
while ($bug31310)
{
let $bug31310= `SELECT 1 - COUNT(*) FROM t2`;
}
SELECT * FROM t1;
--echo # Switch to connection con2
connection con2;
SELECT * FROM t1;
--echo # Switch to connection con1
connection con1;
--echo # 3. test for updated key column:
TRUNCATE t1;
TRUNCATE t2;
INSERT INTO t1 VALUES (1,'init');
BEGIN;
--enable_info
UPDATE t1 SET a = 2, b = CONCAT(b, '+con1') WHERE a = 1;
--disable_info
SELECT * FROM t1;
--echo # Switch to connection con2
connection con2;
--send CALL p1;
--echo # Switch to connection con1
connection con1;
SELECT * FROM t1;
COMMIT;
let $bug31310 = 1;
while ($bug31310)
{
let $bug31310= `SELECT 1 - COUNT(*) FROM t2`;
}
SELECT * FROM t1;
--echo # Switch to connection con2
connection con2;
SELECT * FROM t1;
connection default;
disconnect con1;
disconnect con2;
DROP PROCEDURE p1;
DROP TABLE t1, t2;
--echo End of 5.1 tests
SET SESSION STORAGE_ENGINE = InnoDB;
drop table if exists t1,t2,t3,t1m,t1i,t2m,t2i,t4;
drop procedure if exists p1;
create table t1 (
c_id int(11) not null default '0',
org_id int(11) default null,
......@@ -1419,4 +1420,83 @@ select if(@a=@b,"ok","wrong");
if(@a=@b,"ok","wrong")
ok
drop table t1;
SET SESSION AUTOCOMMIT = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
# Switch to connection con1
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(256))
ENGINE = InnoDB;
INSERT INTO t1 VALUES (1,2);
BEGIN;
UPDATE t1 SET b = 12 WHERE a = 1;
affected rows: 1
info: Rows matched: 1 Changed: 1 Warnings: 0
SELECT * FROM t1;
a b
1 12
# Switch to connection con2
UPDATE t1 SET b = 21 WHERE a = 1;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
# Switch to connection con1
SELECT * FROM t1;
a b
1 12
ROLLBACK;
# 2. test for serialized update:
CREATE TABLE t2 (a INT);
TRUNCATE t1;
INSERT INTO t1 VALUES (1,'init');
CREATE PROCEDURE p1()
BEGIN
UPDATE t1 SET b = CONCAT(b, '+con2') WHERE a = 1;
INSERT INTO t2 VALUES ();
END|
BEGIN;
UPDATE t1 SET b = CONCAT(b, '+con1') WHERE a = 1;
affected rows: 1
info: Rows matched: 1 Changed: 1 Warnings: 0
SELECT * FROM t1;
a b
1 init+con1
# Switch to connection con2
CALL p1;;
# Switch to connection con1
SELECT * FROM t1;
a b
1 init+con1
COMMIT;
SELECT * FROM t1;
a b
1 init+con1
# Switch to connection con2
SELECT * FROM t1;
a b
1 init+con1+con2
# Switch to connection con1
# 3. test for updated key column:
TRUNCATE t1;
TRUNCATE t2;
INSERT INTO t1 VALUES (1,'init');
BEGIN;
UPDATE t1 SET a = 2, b = CONCAT(b, '+con1') WHERE a = 1;
affected rows: 1
info: Rows matched: 1 Changed: 1 Warnings: 0
SELECT * FROM t1;
a b
2 init+con1
# Switch to connection con2
CALL p1;;
# Switch to connection con1
SELECT * FROM t1;
a b
2 init+con1
COMMIT;
SELECT * FROM t1;
a b
2 init+con1
# Switch to connection con2
SELECT * FROM t1;
a b
2 init+con1
DROP PROCEDURE p1;
DROP TABLE t1, t2;
End of 5.1 tests
......@@ -3145,6 +3145,8 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
}
else
{
if (was_semi_consistent_read())
goto scan_it_again;
/*
We need to set this for the last range only, but checking this
condition is more expensive than just setting the result code.
......@@ -3152,10 +3154,10 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
result= HA_ERR_END_OF_FILE;
}
multi_range_curr++;
scan_it_again:
/* Try the next range(s) until one matches a record. */
for (multi_range_curr++;
multi_range_curr < multi_range_end;
multi_range_curr++)
for (; multi_range_curr < multi_range_end; multi_range_curr++)
{
result= read_range_first(multi_range_curr->start_key.keypart_map ?
&multi_range_curr->start_key : 0,
......
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