summaryrefslogtreecommitdiff
path: root/sql/transaction.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/transaction.cc')
-rw-r--r--sql/transaction.cc77
1 files changed, 62 insertions, 15 deletions
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 3359decbcd5..7d8fc89ec8c 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -22,6 +22,7 @@
#include "transaction.h"
#include "rpl_handler.h"
#include "debug_sync.h" // DEBUG_SYNC
+#include "sql_acl.h"
/* Conditions under which the transaction state must not change. */
static bool trans_check(THD *thd)
@@ -134,7 +135,9 @@ bool trans_begin(THD *thd, uint flags)
(thd->variables.option_bits & OPTION_TABLE_LOCK))
{
thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
res= test(ha_commit_trans(thd, TRUE));
}
@@ -150,9 +153,36 @@ bool trans_begin(THD *thd, uint flags)
*/
thd->mdl_context.release_transactional_locks();
+ // The RO/RW options are mutually exclusive.
+ DBUG_ASSERT(!((flags & MYSQL_START_TRANS_OPT_READ_ONLY) &&
+ (flags & MYSQL_START_TRANS_OPT_READ_WRITE)));
+ if (flags & MYSQL_START_TRANS_OPT_READ_ONLY)
+ thd->tx_read_only= true;
+ else if (flags & MYSQL_START_TRANS_OPT_READ_WRITE)
+ {
+ /*
+ Explicitly starting a RW transaction when the server is in
+ read-only mode, is not allowed unless the user has SUPER priv.
+ Implicitly starting a RW transaction is allowed for backward
+ compatibility.
+ */
+ const bool user_is_super=
+ test(thd->security_ctx->master_access & SUPER_ACL);
+ if (opt_readonly && !user_is_super)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ DBUG_RETURN(true);
+ }
+ thd->tx_read_only= false;
+ }
+
thd->variables.option_bits|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
+ if (thd->tx_read_only)
+ thd->server_status|= SERVER_STATUS_IN_TRANS_READONLY;
+ DBUG_PRINT("info", ("setting SERVER_STATUS_IN_TRANS"));
+ /* ha_start_consistent_snapshot() relies on OPTION_BEGIN flag set. */
if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
res= ha_start_consistent_snapshot(thd);
@@ -177,16 +207,18 @@ bool trans_commit(THD *thd)
if (trans_check(thd))
DBUG_RETURN(TRUE);
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
res= ha_commit_trans(thd, TRUE);
- if (res)
/*
if res is non-zero, then ha_commit_trans has rolled back the
transaction, so the hooks for rollback will be called.
*/
- RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+ if (res)
+ (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE));
else
- RUN_HOOK(transaction, after_commit, (thd, FALSE));
+ (void) RUN_HOOK(transaction, after_commit, (thd, FALSE));
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
thd->lex->start_transaction_opt= 0;
@@ -220,7 +252,9 @@ bool trans_commit_implicit(THD *thd)
/* Safety if one did "drop table" on locked tables */
if (!thd->locked_tables_mode)
thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
res= test(ha_commit_trans(thd, TRUE));
}
@@ -229,11 +263,12 @@ bool trans_commit_implicit(THD *thd)
/*
Upon implicit commit, reset the current transaction
- isolation level. We do not care about
+ isolation level and access mode. We do not care about
@@session.completion_type since it's documented
to not have any effect on implicit commit.
*/
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+ thd->tx_read_only= thd->variables.tx_read_only;
DBUG_RETURN(res);
}
@@ -256,9 +291,11 @@ bool trans_rollback(THD *thd)
if (trans_check(thd))
DBUG_RETURN(TRUE);
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
res= ha_rollback_trans(thd, TRUE);
- RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+ (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE));
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
thd->lex->start_transaction_opt= 0;
@@ -298,17 +335,20 @@ bool trans_commit_stmt(THD *thd)
{
res= ha_commit_trans(thd, FALSE);
if (! thd->in_active_multi_stmt_transaction())
+ {
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+ thd->tx_read_only= thd->variables.tx_read_only;
+ }
}
- if (res)
/*
if res is non-zero, then ha_commit_trans has rolled back the
transaction, so the hooks for rollback will be called.
*/
- RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+ if (res)
+ (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE));
else
- RUN_HOOK(transaction, after_commit, (thd, FALSE));
+ (void) RUN_HOOK(transaction, after_commit, (thd, FALSE));
thd->transaction.stmt.reset();
@@ -342,10 +382,13 @@ bool trans_rollback_stmt(THD *thd)
if (thd->transaction_rollback_request && !thd->in_sub_stmt)
ha_rollback_trans(thd, TRUE);
if (! thd->in_active_multi_stmt_transaction())
+ {
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+ thd->tx_read_only= thd->variables.tx_read_only;
+ }
}
- RUN_HOOK(transaction, after_rollback, (thd, FALSE));
+ (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE));
thd->transaction.stmt.reset();
@@ -722,7 +765,9 @@ bool trans_xa_commit(THD *thd)
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
xid_cache_delete(&thd->transaction.xid_state);
thd->transaction.xid_state.xa_state= XA_NOTR;
@@ -769,7 +814,9 @@ bool trans_xa_rollback(THD *thd)
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->server_status&=
+ ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+ DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
xid_cache_delete(&thd->transaction.xid_state);
thd->transaction.xid_state.xa_state= XA_NOTR;