mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 10:14:19 +01:00
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. sql/handler.cc: Fixed bug #31310. The handler::read_multi_range_next method has been modified to retry previous unique range if the previous read was semi-consistent. mysql-test/include/mix1.inc: Added test case for bug #31310. mysql-test/r/innodb_mysql.result: Added test case for bug #31310.
This commit is contained in:
parent
db39be9510
commit
b9805a5a45
3 changed files with 210 additions and 3 deletions
|
@ -29,6 +29,7 @@ eval SET SESSION STORAGE_ENGINE = $engine_type;
|
||||||
|
|
||||||
--disable_warnings
|
--disable_warnings
|
||||||
drop table if exists t1,t2,t3,t1m,t1i,t2m,t2i,t4;
|
drop table if exists t1,t2,t3,t1m,t1i,t2m,t2i,t4;
|
||||||
|
drop procedure if exists p1;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
|
|
||||||
|
|
||||||
|
@ -1146,4 +1147,128 @@ select @b:=f2 from t1;
|
||||||
select if(@a=@b,"ok","wrong");
|
select if(@a=@b,"ok","wrong");
|
||||||
drop table t1;
|
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
|
--echo End of 5.1 tests
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
SET SESSION STORAGE_ENGINE = InnoDB;
|
SET SESSION STORAGE_ENGINE = InnoDB;
|
||||||
drop table if exists t1,t2,t3,t1m,t1i,t2m,t2i,t4;
|
drop table if exists t1,t2,t3,t1m,t1i,t2m,t2i,t4;
|
||||||
|
drop procedure if exists p1;
|
||||||
create table t1 (
|
create table t1 (
|
||||||
c_id int(11) not null default '0',
|
c_id int(11) not null default '0',
|
||||||
org_id int(11) default null,
|
org_id int(11) default null,
|
||||||
|
@ -1419,4 +1420,83 @@ select if(@a=@b,"ok","wrong");
|
||||||
if(@a=@b,"ok","wrong")
|
if(@a=@b,"ok","wrong")
|
||||||
ok
|
ok
|
||||||
drop table t1;
|
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
|
End of 5.1 tests
|
||||||
|
|
|
@ -3145,6 +3145,8 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (was_semi_consistent_read())
|
||||||
|
goto scan_it_again;
|
||||||
/*
|
/*
|
||||||
We need to set this for the last range only, but checking this
|
We need to set this for the last range only, but checking this
|
||||||
condition is more expensive than just setting the result code.
|
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;
|
result= HA_ERR_END_OF_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multi_range_curr++;
|
||||||
|
scan_it_again:
|
||||||
/* Try the next range(s) until one matches a record. */
|
/* Try the next range(s) until one matches a record. */
|
||||||
for (multi_range_curr++;
|
for (; multi_range_curr < multi_range_end; multi_range_curr++)
|
||||||
multi_range_curr < multi_range_end;
|
|
||||||
multi_range_curr++)
|
|
||||||
{
|
{
|
||||||
result= read_range_first(multi_range_curr->start_key.keypart_map ?
|
result= read_range_first(multi_range_curr->start_key.keypart_map ?
|
||||||
&multi_range_curr->start_key : 0,
|
&multi_range_curr->start_key : 0,
|
||||||
|
|
Loading…
Add table
Reference in a new issue