mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
72e978828e
The problem is that a SELECT .. FOR UPDATE statement might open a table and later wait for a impeding global read lock without noticing whether it is holding a table that is being waited upon the the flush phase of the process that took the global read lock. The same problem also affected the following statements: LOCK TABLES .. WRITE UPDATE .. SET (update and multi-table update) TRUNCATE TABLE .. LOAD DATA .. The solution is to make the above statements wait for a impending global read lock before opening the tables. If there is no impending global read lock, the statement raises a temporary protection against global read locks and progresses smoothly towards completion. Important notice: the patch does not try to address all possible cases, only those which are common and can be fixed unintrusively enough for 5.0. mysql-test/r/lock_multi.result: Add test case result for Bug#43230 mysql-test/t/lock_multi.test: Add test case for Bug#43230 sql/sql_lex.cc: Initialize flag. sql/sql_lex.h: Add a flag to the lexer. sql/sql_parse.cc: Wait for the global read lock is a write lock is going to be taken. The wait is done before opening tables. sql/sql_yacc.yy: Protect against the GRL if its a SELECT .. FOR UPDATE or LOCK TABLES .. WRITE statement.
190 lines
4.5 KiB
Text
190 lines
4.5 KiB
Text
drop table if exists t1,t2;
|
|
create table t1(n int);
|
|
insert into t1 values (1);
|
|
lock tables t1 write;
|
|
update low_priority t1 set n = 4;
|
|
select n from t1;
|
|
unlock tables;
|
|
n
|
|
4
|
|
drop table t1;
|
|
create table t1(n int);
|
|
insert into t1 values (1);
|
|
lock tables t1 read;
|
|
update low_priority t1 set n = 4;
|
|
select n from t1;
|
|
unlock tables;
|
|
n
|
|
1
|
|
drop table t1;
|
|
create table t1 (a int, b int);
|
|
create table t2 (c int, d int);
|
|
insert into t1 values(1,1);
|
|
insert into t1 values(2,2);
|
|
insert into t2 values(1,2);
|
|
lock table t1 read;
|
|
update t1,t2 set c=a where b=d;
|
|
select c from t2;
|
|
c
|
|
2
|
|
drop table t1;
|
|
drop table t2;
|
|
create table t1 (a int);
|
|
create table t2 (a int);
|
|
lock table t1 write, t2 write;
|
|
insert t1 select * from t2;
|
|
drop table t2;
|
|
ERROR 42S02: Table 'test.t2' doesn't exist
|
|
drop table t1;
|
|
create table t1(a int);
|
|
lock tables t1 write;
|
|
show columns from t1;
|
|
Field Type Null Key Default Extra
|
|
a int(11) YES NULL
|
|
unlock tables;
|
|
drop table t1;
|
|
CREATE DATABASE mysqltest_1;
|
|
FLUSH TABLES WITH READ LOCK;
|
|
DROP DATABASE mysqltest_1;
|
|
DROP DATABASE mysqltest_1;
|
|
ERROR HY000: Can't execute the query because you have a conflicting read lock
|
|
UNLOCK TABLES;
|
|
DROP DATABASE mysqltest_1;
|
|
ERROR HY000: Can't drop database 'mysqltest_1'; database doesn't exist
|
|
USE mysql;
|
|
LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE;
|
|
FLUSH TABLES;
|
|
USE mysql;
|
|
SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1;
|
|
OPTIMIZE TABLES columns_priv, db, host, user;
|
|
Table Op Msg_type Msg_text
|
|
mysql.columns_priv optimize status OK
|
|
mysql.db optimize status OK
|
|
mysql.host optimize status OK
|
|
mysql.user optimize status OK
|
|
UNLOCK TABLES;
|
|
Select_priv
|
|
N
|
|
USE test;
|
|
use test;
|
|
CREATE TABLE t1 (c1 int);
|
|
LOCK TABLE t1 WRITE;
|
|
FLUSH TABLES WITH READ LOCK;
|
|
CREATE TABLE t2 (c1 int);
|
|
UNLOCK TABLES;
|
|
UNLOCK TABLES;
|
|
DROP TABLE t1, t2;
|
|
CREATE TABLE t1 (c1 int);
|
|
LOCK TABLE t1 WRITE;
|
|
FLUSH TABLES WITH READ LOCK;
|
|
CREATE TABLE t2 AS SELECT * FROM t1;
|
|
ERROR HY000: Table 't2' was not locked with LOCK TABLES
|
|
UNLOCK TABLES;
|
|
UNLOCK TABLES;
|
|
DROP TABLE t1;
|
|
create table t1 (f1 int(12) unsigned not null auto_increment, primary key(f1)) engine=innodb;
|
|
lock tables t1 write;
|
|
alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; //
|
|
alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; //
|
|
unlock tables;
|
|
drop table t1;
|
|
drop table if exists t1;
|
|
create table t1 (a int);
|
|
connection: locker
|
|
lock tables t1 read;
|
|
connection: writer
|
|
create table t2 like t1;
|
|
connection: default
|
|
kill query
|
|
ERROR 70100: Query execution was interrupted
|
|
unlock tables;
|
|
drop table t1;
|
|
CREATE TABLE t1 (
|
|
a int(11) unsigned default NULL,
|
|
b varchar(255) default NULL,
|
|
UNIQUE KEY a (a),
|
|
KEY b (b)
|
|
);
|
|
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
|
|
CREATE TABLE t2 SELECT * FROM t1;
|
|
CREATE TABLE t3 SELECT * FROM t1;
|
|
# test altering of columns that multiupdate doesn't use
|
|
# normal mode
|
|
# PS mode
|
|
# test altering of columns that multiupdate uses
|
|
# normal mode
|
|
# PS mode
|
|
DROP TABLE t1, t2, t3;
|
|
CREATE TABLE t1( a INT, b INT );
|
|
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4);
|
|
# 1. test regular tables
|
|
# 1.1. test altering of columns that multiupdate doesn't use
|
|
# 1.1.1. normal mode
|
|
# 1.1.2. PS mode
|
|
# 1.2. test altering of columns that multiupdate uses
|
|
# 1.2.1. normal mode
|
|
# 1.2.2. PS mode
|
|
ALTER TABLE t1 ADD COLUMN a INT;
|
|
# 2. test UNIONs
|
|
# 2.1. test altering of columns that multiupdate doesn't use
|
|
# 2.1.1. normal mode
|
|
# 2.1.2. PS mode
|
|
# 2.2. test altering of columns that multiupdate uses
|
|
# 2.2.1. normal mode
|
|
# 2.2.2. PS mode
|
|
DROP TABLE t1;
|
|
create table t1 (a int);
|
|
create table t2 like t1;
|
|
# con1
|
|
lock tables t1 write;
|
|
# con2
|
|
flush tables with read lock;
|
|
# con5
|
|
# global read lock is taken
|
|
# con3
|
|
select * from t2 for update;
|
|
# waiting for release of read lock
|
|
# con4
|
|
# would hang and later cause a deadlock
|
|
flush tables t2;
|
|
# clean up
|
|
unlock tables;
|
|
unlock tables;
|
|
a
|
|
drop table t1,t2;
|
|
#
|
|
# Lightweight version:
|
|
# Ensure that the wait for a GRL is done before opening tables.
|
|
#
|
|
create table t1 (a int);
|
|
create table t2 like t1;
|
|
#
|
|
# UPDATE
|
|
#
|
|
# default
|
|
flush tables with read lock;
|
|
# con1
|
|
update t2 set a = 1;
|
|
# default
|
|
# statement is waiting for release of read lock
|
|
# con2
|
|
flush table t2;
|
|
# default
|
|
unlock tables;
|
|
# con1
|
|
#
|
|
# LOCK TABLES .. WRITE
|
|
#
|
|
# default
|
|
flush tables with read lock;
|
|
# con1
|
|
lock tables t2 write;
|
|
# default
|
|
# statement is waiting for release of read lock
|
|
# con2
|
|
flush table t2;
|
|
# default
|
|
unlock tables;
|
|
# con1
|
|
unlock tables;
|
|
drop table t1,t2;
|