Commit 77b7a862 authored by unknown's avatar unknown
Browse files

WL#3602 (SET GLOBAL READONLY)

Bug#11733 (COMMITs should not happen if read-only is set)
Bug#22009 (Can write to a read-only server under some circumstances)

See the work log for details

The change consist of
a) acquiring the global read lock in SET GLOBAL READONLY
b) honoring opt_readonly in ha_commit_trans(),
c) honoring opt_readonly in mysql_lock_tables().

a) takes care of the server stability,
b) makes the transactional tables safe (Bug 11733)
c) makes the non transactional tables safe (Bug 22009)


mysql-test/r/read_only.result:
  WL#3602 (SET GLOBAL READONLY)
mysql-test/t/read_only.test:
  WL#3602 (SET GLOBAL READONLY)
sql/handler.cc:
  WL#3602 (SET GLOBAL READONLY)
sql/lock.cc:
  WL#3602 (SET GLOBAL READONLY)
sql/set_var.cc:
  WL#3602 (SET GLOBAL READONLY)
sql/set_var.h:
  WL#3602 (SET GLOBAL READONLY)
mysql-test/r/read_only_innodb.result:
  WL#3602 (SET GLOBAL READONLY)
mysql-test/t/read_only_innodb.test:
  WL#3602 (SET GLOBAL READONLY)
parent 78be2cdc
Loading
Loading
Loading
Loading
+51 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
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;
+108 −2
Original line number Diff line number Diff line
@@ -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;
drop table t1,t2;
drop user test@localhost;
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;
+43 −0
Original line number Diff line number Diff line
# 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;
+9 −0
Original line number Diff line number Diff line
@@ -692,6 +692,15 @@ int ha_commit_trans(THD *thd, bool all)
      ha_rollback_trans(thd, all);
      DBUG_RETURN(1);
    }

    if (is_real_trans && opt_readonly)
    {
      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 */
Loading