mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
Merge malff@bk-internal.mysql.com:/home/bk/mysql-5.1-runtime
into weblab.(none):/home/marcsql/TREE/mysql-5.1-11733_topdown
This commit is contained in:
commit
a1b260df75
11 changed files with 548 additions and 4 deletions
|
@ -39,6 +39,56 @@ delete t1 from t1,t3 where t1.a=t3.a;
|
|||
drop table t1;
|
||||
insert into t1 values(1);
|
||||
ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
|
||||
set global read_only=0;
|
||||
lock table t1 write;
|
||||
lock table t2 write;
|
||||
set global read_only=1;
|
||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
||||
unlock tables ;
|
||||
set global read_only=1;
|
||||
select @@global.read_only;
|
||||
@@global.read_only
|
||||
0
|
||||
unlock tables ;
|
||||
select @@global.read_only;
|
||||
@@global.read_only
|
||||
1
|
||||
set global read_only=0;
|
||||
lock table t1 read;
|
||||
lock table t2 read;
|
||||
set global read_only=1;
|
||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
||||
unlock tables ;
|
||||
set global read_only=1;
|
||||
select @@global.read_only;
|
||||
@@global.read_only
|
||||
0
|
||||
unlock tables ;
|
||||
select @@global.read_only;
|
||||
@@global.read_only
|
||||
1
|
||||
set global read_only=0;
|
||||
BEGIN;
|
||||
BEGIN;
|
||||
set global read_only=1;
|
||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
||||
ROLLBACK;
|
||||
set global read_only=1;
|
||||
select @@global.read_only;
|
||||
@@global.read_only
|
||||
1
|
||||
ROLLBACK;
|
||||
set global read_only=0;
|
||||
flush tables with read lock;
|
||||
set global read_only=1;
|
||||
unlock tables;
|
||||
set global read_only=0;
|
||||
flush tables with read lock;
|
||||
set global read_only=1;
|
||||
select @@global.read_only;
|
||||
@@global.read_only
|
||||
1
|
||||
unlock tables;
|
||||
set global read_only=0;
|
||||
drop table t1,t2;
|
||||
drop user test@localhost;
|
||||
set global read_only=0;
|
||||
|
|
18
mysql-test/r/read_only_innodb.result
Normal file
18
mysql-test/r/read_only_innodb.result
Normal file
|
@ -0,0 +1,18 @@
|
|||
DROP TABLE IF EXISTS table_11733 ;
|
||||
grant CREATE, SELECT, DROP on *.* to test@localhost;
|
||||
set global read_only=0;
|
||||
create table table_11733 (a int) engine=InnoDb;
|
||||
BEGIN;
|
||||
insert into table_11733 values(11733);
|
||||
set global read_only=1;
|
||||
select @@global.read_only;
|
||||
@@global.read_only
|
||||
1
|
||||
select * from table_11733 ;
|
||||
a
|
||||
11733
|
||||
COMMIT;
|
||||
ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
|
||||
set global read_only=0;
|
||||
drop table table_11733 ;
|
||||
drop user test@localhost;
|
113
mysql-test/r/rpl_read_only.result
Normal file
113
mysql-test/r/rpl_read_only.result
Normal file
|
@ -0,0 +1,113 @@
|
|||
stop slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
reset master;
|
||||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
create table t1(a int) engine=InnoDB;
|
||||
create table t2(a int) engine=MyISAM;
|
||||
insert into t1 values(1001);
|
||||
insert into t2 values(2001);
|
||||
set global read_only=1;
|
||||
select @@read_only;
|
||||
@@read_only
|
||||
1
|
||||
select * from t1;
|
||||
a
|
||||
1001
|
||||
select * from t2;
|
||||
a
|
||||
2001
|
||||
select @@read_only;
|
||||
@@read_only
|
||||
0
|
||||
select * from t1;
|
||||
a
|
||||
1001
|
||||
select * from t2;
|
||||
a
|
||||
2001
|
||||
set global read_only=0;
|
||||
BEGIN;
|
||||
insert into t1 values(1002);
|
||||
insert into t2 values(2002);
|
||||
BEGIN;
|
||||
insert into t1 values(1003);
|
||||
insert into t2 values(2003);
|
||||
set global read_only=1;
|
||||
COMMIT;
|
||||
COMMIT;
|
||||
ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
|
||||
set global read_only=0;
|
||||
insert into t1 values(1004);
|
||||
insert into t2 values(2004);
|
||||
select * from t1;
|
||||
a
|
||||
1001
|
||||
1002
|
||||
1004
|
||||
select * from t2;
|
||||
a
|
||||
2001
|
||||
2002
|
||||
2003
|
||||
2004
|
||||
select * from t1;
|
||||
a
|
||||
1001
|
||||
1002
|
||||
1004
|
||||
select * from t2;
|
||||
a
|
||||
2001
|
||||
2002
|
||||
2003
|
||||
2004
|
||||
set global read_only=1;
|
||||
select @@read_only;
|
||||
@@read_only
|
||||
1
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
show create table t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE `t2` (
|
||||
`a` int(11) DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert into t1 values(1005);
|
||||
insert into t2 values(2005);
|
||||
select * from t1;
|
||||
a
|
||||
1001
|
||||
1002
|
||||
1004
|
||||
1005
|
||||
select * from t2;
|
||||
a
|
||||
2001
|
||||
2002
|
||||
2003
|
||||
2004
|
||||
2005
|
||||
select * from t1;
|
||||
a
|
||||
1001
|
||||
1002
|
||||
1004
|
||||
1005
|
||||
select * from t2;
|
||||
a
|
||||
2001
|
||||
2002
|
||||
2003
|
||||
2004
|
||||
2005
|
||||
insert into t1 values(1006);
|
||||
ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
|
||||
insert into t2 values(2006);
|
||||
ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
|
||||
drop table t1;
|
||||
drop table t2;
|
|
@ -101,8 +101,114 @@ drop table t1;
|
|||
--error 1290
|
||||
insert into t1 values(1);
|
||||
|
||||
#
|
||||
# BUG#11733: COMMITs should not happen if read-only is set
|
||||
#
|
||||
|
||||
# LOCK TABLE ... WRITE / READ_ONLY
|
||||
# - is an error in the same connection
|
||||
# - is ok in a different connection
|
||||
|
||||
connection default;
|
||||
set global read_only=0;
|
||||
lock table t1 write;
|
||||
|
||||
connection con1;
|
||||
lock table t2 write;
|
||||
|
||||
connection default;
|
||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
||||
set global read_only=1;
|
||||
unlock tables ;
|
||||
# The following call blocks until con1 releases the write lock.
|
||||
# Blocking is expected.
|
||||
send set global read_only=1;
|
||||
|
||||
connection con1;
|
||||
--sleep 1
|
||||
select @@global.read_only;
|
||||
unlock tables ;
|
||||
--sleep 1
|
||||
select @@global.read_only;
|
||||
|
||||
connection default;
|
||||
reap;
|
||||
|
||||
# LOCK TABLE ... READ / READ_ONLY
|
||||
# - is an error in the same connection
|
||||
# - is ok in a different connection
|
||||
|
||||
connection default;
|
||||
set global read_only=0;
|
||||
lock table t1 read;
|
||||
|
||||
connection con1;
|
||||
lock table t2 read;
|
||||
|
||||
connection default;
|
||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
||||
set global read_only=1;
|
||||
unlock tables ;
|
||||
# The following call blocks until con1 releases the read lock.
|
||||
# Blocking is a limitation, and could be improved.
|
||||
send set global read_only=1;
|
||||
|
||||
connection con1;
|
||||
--sleep 1
|
||||
select @@global.read_only;
|
||||
unlock tables ;
|
||||
--sleep 1
|
||||
select @@global.read_only;
|
||||
|
||||
connection default;
|
||||
reap;
|
||||
|
||||
# pending transaction / READ_ONLY
|
||||
# - is an error in the same connection
|
||||
# - is ok in a different connection
|
||||
|
||||
connection default;
|
||||
set global read_only=0;
|
||||
BEGIN;
|
||||
|
||||
connection con1;
|
||||
BEGIN;
|
||||
|
||||
connection default;
|
||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
||||
set global read_only=1;
|
||||
ROLLBACK;
|
||||
set global read_only=1;
|
||||
|
||||
connection con1;
|
||||
select @@global.read_only;
|
||||
ROLLBACK;
|
||||
|
||||
# Verify that FLUSH TABLES WITH READ LOCK do not block READ_ONLY
|
||||
# - in the same SUPER connection
|
||||
# - in another SUPER connection
|
||||
|
||||
connection default;
|
||||
set global read_only=0;
|
||||
flush tables with read lock;
|
||||
set global read_only=1;
|
||||
unlock tables;
|
||||
|
||||
connect (root2,localhost,root,,test);
|
||||
|
||||
connection default;
|
||||
set global read_only=0;
|
||||
flush tables with read lock;
|
||||
|
||||
connection root2;
|
||||
set global read_only=1;
|
||||
|
||||
connection default;
|
||||
select @@global.read_only;
|
||||
unlock tables;
|
||||
|
||||
# Cleanup
|
||||
connection default;
|
||||
set global read_only=0;
|
||||
drop table t1,t2;
|
||||
drop user test@localhost;
|
||||
|
||||
set global read_only=0;
|
||||
|
|
43
mysql-test/t/read_only_innodb.test
Normal file
43
mysql-test/t/read_only_innodb.test
Normal file
|
@ -0,0 +1,43 @@
|
|||
# should work with embedded server after mysqltest is fixed
|
||||
-- source include/not_embedded.inc
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
#
|
||||
# BUG#11733: COMMITs should not happen if read-only is set
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS table_11733 ;
|
||||
--enable_warnings
|
||||
|
||||
# READ_ONLY does nothing to SUPER users
|
||||
# so we use a non-SUPER one:
|
||||
|
||||
grant CREATE, SELECT, DROP on *.* to test@localhost;
|
||||
|
||||
connect (con1,localhost,test,,test);
|
||||
|
||||
connection default;
|
||||
set global read_only=0;
|
||||
|
||||
# Any transactional engine will do
|
||||
create table table_11733 (a int) engine=InnoDb;
|
||||
|
||||
connection con1;
|
||||
BEGIN;
|
||||
insert into table_11733 values(11733);
|
||||
|
||||
connection default;
|
||||
set global read_only=1;
|
||||
|
||||
connection con1;
|
||||
select @@global.read_only;
|
||||
select * from table_11733 ;
|
||||
-- error ER_OPTION_PREVENTS_STATEMENT
|
||||
COMMIT;
|
||||
|
||||
connection default;
|
||||
set global read_only=0;
|
||||
drop table table_11733 ;
|
||||
drop user test@localhost;
|
||||
|
1
mysql-test/t/rpl_read_only-slave.opt
Normal file
1
mysql-test/t/rpl_read_only-slave.opt
Normal file
|
@ -0,0 +1 @@
|
|||
--innodb
|
105
mysql-test/t/rpl_read_only.test
Normal file
105
mysql-test/t/rpl_read_only.test
Normal file
|
@ -0,0 +1,105 @@
|
|||
# Test case for BUG #11733
|
||||
-- source include/master-slave.inc
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
# Setting the master readonly :
|
||||
# - the variable @@readonly is not replicated on the slave
|
||||
|
||||
connect (master2,127.0.0.1,test,,test,$MASTER_MYPORT,);
|
||||
connect (slave2,127.0.0.1,test,,test,$SLAVE_MYPORT,);
|
||||
|
||||
connection master1;
|
||||
|
||||
create table t1(a int) engine=InnoDB;
|
||||
create table t2(a int) engine=MyISAM;
|
||||
insert into t1 values(1001);
|
||||
insert into t2 values(2001);
|
||||
|
||||
connection master;
|
||||
set global read_only=1;
|
||||
|
||||
connection master1;
|
||||
select @@read_only;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
sync_slave_with_master;
|
||||
select @@read_only;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
# - replication of transactions
|
||||
connection master;
|
||||
set global read_only=0;
|
||||
|
||||
connection master1;
|
||||
BEGIN;
|
||||
insert into t1 values(1002);
|
||||
insert into t2 values(2002);
|
||||
|
||||
connection master2;
|
||||
BEGIN;
|
||||
insert into t1 values(1003);
|
||||
insert into t2 values(2003);
|
||||
|
||||
connection master;
|
||||
set global read_only=1;
|
||||
|
||||
connection master1;
|
||||
## works even with read_only=1, because master1 is root
|
||||
COMMIT;
|
||||
|
||||
connection master2;
|
||||
--error ER_OPTION_PREVENTS_STATEMENT
|
||||
COMMIT;
|
||||
|
||||
connection master;
|
||||
set global read_only=0;
|
||||
|
||||
connection master1;
|
||||
insert into t1 values(1004);
|
||||
insert into t2 values(2004);
|
||||
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
sync_slave_with_master;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
# Setting the slave readonly : replication will pass
|
||||
#
|
||||
connection slave1;
|
||||
set global read_only=1;
|
||||
|
||||
connection slave;
|
||||
select @@read_only;
|
||||
# Make sure the replicated table is also transactional
|
||||
show create table t1;
|
||||
# Make sure the replicated table is not transactional
|
||||
show create table t2;
|
||||
|
||||
connection master;
|
||||
insert into t1 values(1005);
|
||||
insert into t2 values(2005);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
sync_slave_with_master;
|
||||
connection slave;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
# Non root user can not write on the slave
|
||||
connection slave2;
|
||||
--error ER_OPTION_PREVENTS_STATEMENT
|
||||
insert into t1 values(1006);
|
||||
--error ER_OPTION_PREVENTS_STATEMENT
|
||||
insert into t2 values(2006);
|
||||
|
||||
## Cleanup
|
||||
connection master;
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
sync_slave_with_master;
|
||||
|
|
@ -692,6 +692,19 @@ int ha_commit_trans(THD *thd, bool all)
|
|||
ha_rollback_trans(thd, all);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if ( is_real_trans
|
||||
&& opt_readonly
|
||||
&& ! (thd->security_ctx->master_access & SUPER_ACL)
|
||||
&& ! thd->slave_thread
|
||||
)
|
||||
{
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
|
||||
ha_rollback_trans(thd, all);
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF("crash_commit_before", abort(););
|
||||
|
||||
/* Close all cursors that can not survive COMMIT */
|
||||
|
|
17
sql/lock.cc
17
sql/lock.cc
|
@ -151,6 +151,23 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
|
|||
}
|
||||
}
|
||||
|
||||
if ( write_lock_used
|
||||
&& opt_readonly
|
||||
&& ! (thd->security_ctx->master_access & SUPER_ACL)
|
||||
&& ! thd->slave_thread
|
||||
)
|
||||
{
|
||||
/*
|
||||
Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
|
||||
We do not wait for READ_ONLY=0, and fail.
|
||||
*/
|
||||
reset_lock_data(sql_lock);
|
||||
my_free((gptr) sql_lock, MYF(0));
|
||||
sql_lock=0;
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
|
||||
break;
|
||||
}
|
||||
|
||||
thd->proc_info="System lock";
|
||||
DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
|
||||
if (lock_external(thd, tables, count))
|
||||
|
|
|
@ -369,7 +369,7 @@ sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size",
|
|||
&SV::preload_buff_size);
|
||||
sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
|
||||
&SV::read_buff_size);
|
||||
sys_var_bool_ptr sys_readonly("read_only", &opt_readonly);
|
||||
sys_var_opt_readonly sys_readonly("read_only", &opt_readonly);
|
||||
sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size",
|
||||
&SV::read_rnd_buff_size);
|
||||
sys_var_thd_ulong sys_div_precincrement("div_precision_increment",
|
||||
|
@ -3854,6 +3854,70 @@ bool sys_var_trust_routine_creators::update(THD *thd, set_var *var)
|
|||
return sys_var_bool_ptr::update(thd, var);
|
||||
}
|
||||
|
||||
bool sys_var_opt_readonly::update(THD *thd, set_var *var)
|
||||
{
|
||||
bool result;
|
||||
|
||||
DBUG_ENTER("sys_var_opt_readonly::update");
|
||||
|
||||
/* Prevent self dead-lock */
|
||||
if (thd->locked_tables || thd->active_transaction())
|
||||
{
|
||||
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
|
||||
if (thd->global_read_lock)
|
||||
{
|
||||
/*
|
||||
This connection already holds the global read lock.
|
||||
This can be the case with:
|
||||
- FLUSH TABLES WITH READ LOCK
|
||||
- SET GLOBAL READ_ONLY = 1
|
||||
*/
|
||||
result= sys_var_bool_ptr::update(thd, var);
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
/*
|
||||
Perform a 'FLUSH TABLES WITH READ LOCK'.
|
||||
This is a 3 step process:
|
||||
- [1] lock_global_read_lock()
|
||||
- [2] close_cached_tables()
|
||||
- [3] make_global_read_lock_block_commit()
|
||||
[1] prevents new connections from obtaining tables locked for write.
|
||||
[2] waits until all existing connections close their tables.
|
||||
[3] prevents transactions from being committed.
|
||||
*/
|
||||
|
||||
if (lock_global_read_lock(thd))
|
||||
DBUG_RETURN(true);
|
||||
|
||||
/*
|
||||
This call will be blocked by any connection holding a READ or WRITE lock.
|
||||
Ideally, we want to wait only for pending WRITE locks, but since:
|
||||
con 1> LOCK TABLE T FOR READ;
|
||||
con 2> LOCK TABLE T FOR WRITE; (blocked by con 1)
|
||||
con 3> SET GLOBAL READ ONLY=1; (blocked by con 2)
|
||||
can cause to wait on a read lock, it's required for the client application
|
||||
to unlock everything, and acceptable for the server to wait on all locks.
|
||||
*/
|
||||
if (close_cached_tables(thd, true, NULL, false))
|
||||
goto end_with_read_lock;
|
||||
|
||||
if (result= make_global_read_lock_block_commit(thd))
|
||||
goto end_with_read_lock;
|
||||
|
||||
/* Change the opt_readonly system variable, safe because the lock is held */
|
||||
result= sys_var_bool_ptr::update(thd, var);
|
||||
|
||||
end_with_read_lock:
|
||||
/* Release the lock */
|
||||
unlock_global_read_lock(thd);
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
||||
/* even session variable here requires SUPER, because of -#o,file */
|
||||
bool sys_var_thd_dbug::check(THD *thd, set_var *var)
|
||||
{
|
||||
|
|
|
@ -905,6 +905,20 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
Handler for setting the system variable --read-only.
|
||||
*/
|
||||
|
||||
class sys_var_opt_readonly :public sys_var_bool_ptr
|
||||
{
|
||||
public:
|
||||
sys_var_opt_readonly(const char *name_arg, my_bool *value_arg) :
|
||||
sys_var_bool_ptr(name_arg, value_arg) {};
|
||||
~sys_var_opt_readonly() {};
|
||||
bool update(THD *thd, set_var *var);
|
||||
};
|
||||
|
||||
|
||||
class sys_var_thd_lc_time_names :public sys_var_thd
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in a new issue