diff options
-rw-r--r-- | mysql-test/suite/binlog/r/binlog_dmls_on_tmp_tables_readonly.result | 58 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_dmls_on_tmp_tables_readonly.test | 90 | ||||
-rw-r--r-- | sql/handler.cc | 2 | ||||
-rw-r--r-- | sql/log.cc | 8 | ||||
-rw-r--r-- | sql/log.h | 2 | ||||
-rw-r--r-- | sql/log_event.cc | 3 |
6 files changed, 155 insertions, 8 deletions
diff --git a/mysql-test/suite/binlog/r/binlog_dmls_on_tmp_tables_readonly.result b/mysql-test/suite/binlog/r/binlog_dmls_on_tmp_tables_readonly.result new file mode 100644 index 00000000000..1dfac08e762 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_dmls_on_tmp_tables_readonly.result @@ -0,0 +1,58 @@ +DROP TABLE IF EXISTS t1 ; +# 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=1; +connection con1; +CREATE TEMPORARY TABLE t1 (a INT) ENGINE=INNODB; +# Test INSERTS with autocommit being off and on. +BEGIN; +INSERT INTO t1 VALUES (10); +COMMIT; +INSERT INTO t1 VALUES (20); +# Test UPDATES with autocommit being off and on. +BEGIN; +UPDATE t1 SET a=30 WHERE a=10; +COMMIT; +UPDATE t1 SET a=40 WHERE a=20; +connection default; +SET GLOBAL READ_ONLY=0; +# Test scenario where global read_only is enabled in the middle of transaction. +# Test INSERT operations on temporary tables, INSERTs should be successful even +# when global read_only is enabled. +connection con1; +BEGIN; +INSERT INTO t1 VALUES(50); +connection default; +SET GLOBAL READ_ONLY=1; +connection con1; +SELECT @@GLOBAL.READ_ONLY; +@@GLOBAL.READ_ONLY +1 +COMMIT; +connection default; +SET GLOBAL READ_ONLY=0; +# Test UPDATE operations on temporary tables, UPDATEs should be successful even +# when global read_only is enabled. +connection con1; +BEGIN; +UPDATE t1 SET a=60 WHERE a=50; +connection default; +SET GLOBAL READ_ONLY=1; +connection con1; +SELECT @@GLOBAL.READ_ONLY; +@@GLOBAL.READ_ONLY +1 +COMMIT; +SELECT * FROM t1; +a +30 +40 +60 +# Clean up +connection default; +SET GLOBAL READ_ONLY=0; +disconnect con1; +DROP USER test@localhost; diff --git a/mysql-test/suite/binlog/t/binlog_dmls_on_tmp_tables_readonly.test b/mysql-test/suite/binlog/t/binlog_dmls_on_tmp_tables_readonly.test new file mode 100644 index 00000000000..30a6471bf61 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_dmls_on_tmp_tables_readonly.test @@ -0,0 +1,90 @@ +# ==== Purpose ==== +# +# Check that DMLs are allowed on temporary tables, when server is in read only +# mode and binary log is enabled with binlog-format being stmt/mixed mode. +# +# ==== Implementation ==== +# +# Start the server with binary log being enabled. Mark the server as read only. +# Create a non-SUPER user and let the user to create a temporary table and +# perform DML operations on that temporary table. DMLs should not be blocked +# with a 'server read-only mode' error. +# +# ==== References ==== +# +# Bug#12818255: READ-ONLY OPTION DOES NOT ALLOW INSERTS/UPDATES ON TEMPORARY +# TABLES +# Bug#14294223: CHANGES NOT ALLOWED TO TEMPORARY TABLES ON READ-ONLY SERVERS +############################################################################### +--source include/have_log_bin.inc +--disable_warnings +DROP TABLE IF EXISTS t1 ; +--enable_warnings + +--enable_connect_log +--echo # READ_ONLY does nothing to SUPER users +--echo # 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=1; + +connection con1; +CREATE TEMPORARY TABLE t1 (a INT) ENGINE=INNODB; + +--echo # Test INSERTS with autocommit being off and on. +BEGIN; +INSERT INTO t1 VALUES (10); +COMMIT; +INSERT INTO t1 VALUES (20); + +--echo # Test UPDATES with autocommit being off and on. +BEGIN; +UPDATE t1 SET a=30 WHERE a=10; +COMMIT; +UPDATE t1 SET a=40 WHERE a=20; + +connection default; +SET GLOBAL READ_ONLY=0; + +--echo # Test scenario where global read_only is enabled in the middle of transaction. +--echo # Test INSERT operations on temporary tables, INSERTs should be successful even +--echo # when global read_only is enabled. +connection con1; +BEGIN; +INSERT INTO t1 VALUES(50); + +connection default; +SET GLOBAL READ_ONLY=1; + +connection con1; +SELECT @@GLOBAL.READ_ONLY; +COMMIT; + +connection default; +SET GLOBAL READ_ONLY=0; + +--echo # Test UPDATE operations on temporary tables, UPDATEs should be successful even +--echo # when global read_only is enabled. +connection con1; +BEGIN; +UPDATE t1 SET a=60 WHERE a=50; + +connection default; +SET GLOBAL READ_ONLY=1; + +connection con1; +SELECT @@GLOBAL.READ_ONLY; +COMMIT; + +SELECT * FROM t1; + +--echo # Clean up +connection default; +SET GLOBAL READ_ONLY=0; + +disconnect con1; +DROP USER test@localhost; +--disable_connect_log diff --git a/sql/handler.cc b/sql/handler.cc index 9d57cba73dc..79cf7ac2fd9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1279,7 +1279,7 @@ int ha_commit_trans(THD *thd, bool all) DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); } - if (rw_trans && + if (rw_trans && stmt_has_updated_trans_table(ha_info) && opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) && !thd->slave_thread) diff --git a/sql/log.cc b/sql/log.cc index a7f05905514..e0ba93b0959 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4562,17 +4562,15 @@ trans_has_updated_trans_table(const THD* thd) This function checks if a transactional table was updated by the current statement. - @param thd The client thread that executed the current statement. + @param ha_list Registered storage engine handler list. @return @c true if a transactional table was updated, @c false otherwise. */ bool -stmt_has_updated_trans_table(const THD *thd) +stmt_has_updated_trans_table(Ha_trx_info* ha_list) { Ha_trx_info *ha_info; - - for (ha_info= thd->transaction.stmt.ha_list; ha_info; - ha_info= ha_info->next()) + for (ha_info= ha_list; ha_info; ha_info= ha_info->next()) { if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) return (TRUE); diff --git a/sql/log.h b/sql/log.h index 7d1c3161ac2..dd09cb41026 100644 --- a/sql/log.h +++ b/sql/log.h @@ -25,7 +25,7 @@ class Master_info; class Format_description_log_event; bool trans_has_updated_trans_table(const THD* thd); -bool stmt_has_updated_trans_table(const THD *thd); +bool stmt_has_updated_trans_table(Ha_trx_info* ha_list); bool use_trans_cache(const THD* thd, bool is_transactional); bool ending_trans(THD* thd, const bool all); bool ending_single_stmt_trans(THD* thd, const bool all); diff --git a/sql/log_event.cc b/sql/log_event.cc index 702cf1d575a..5dbeb1eb4b9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2637,7 +2637,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, { cache_type= Log_event::EVENT_NO_CACHE; } - else if (using_trans || trx_cache || stmt_has_updated_trans_table(thd) || + else if (using_trans || trx_cache || + stmt_has_updated_trans_table(thd->transaction.stmt.ha_list) || thd->lex->is_mixed_stmt_unsafe(thd->in_multi_stmt_transaction_mode(), thd->variables.binlog_direct_non_trans_update, trans_has_updated_trans_table(thd), |