18 #include "transaction.h"
19 #include "rpl_handler.h"
33 bool trans_check_state(THD *thd)
35 enum xa_states xa_state= thd->transaction.xid_state.xa_state;
36 DBUG_ENTER(
"trans_check");
42 DBUG_ASSERT(thd->transaction.stmt.is_empty());
44 if (unlikely(thd->in_sub_stmt))
45 my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
46 if (xa_state != XA_NOTR)
47 my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
66 static bool xa_trans_rolled_back(XID_STATE *xid_state)
68 if (xid_state->rm_error)
70 switch (xid_state->rm_error) {
71 case ER_LOCK_WAIT_TIMEOUT:
72 my_error(ER_XA_RBTIMEOUT, MYF(0));
74 case ER_LOCK_DEADLOCK:
75 my_error(ER_XA_RBDEADLOCK, MYF(0));
78 my_error(ER_XA_RBROLLBACK, MYF(0));
80 xid_state->xa_state= XA_ROLLBACK_ONLY;
83 return (xid_state->xa_state == XA_ROLLBACK_ONLY);
97 static bool xa_trans_force_rollback(THD *thd)
104 thd->transaction.xid_state.rm_error= 0;
105 if (ha_rollback_trans(thd,
true))
107 my_error(ER_XAER_RMERR, MYF(0));
127 bool trans_begin(THD *thd, uint
flags)
130 DBUG_ENTER(
"trans_begin");
132 if (trans_check_state(thd))
135 thd->locked_tables_list.unlock_locked_tables(thd);
137 DBUG_ASSERT(!thd->locked_tables_mode);
139 if (thd->in_multi_stmt_transaction_mode() ||
140 (thd->variables.option_bits & OPTION_TABLE_LOCK))
142 thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
144 ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
145 DBUG_PRINT(
"info", (
"clearing SERVER_STATUS_IN_TRANS"));
149 thd->variables.option_bits&= ~OPTION_BEGIN;
150 thd->transaction.all.reset_unsafe_rollback_flags();
159 thd->mdl_context.release_transactional_locks();
162 DBUG_ASSERT(!((flags & MYSQL_START_TRANS_OPT_READ_ONLY) &&
163 (flags & MYSQL_START_TRANS_OPT_READ_WRITE)));
164 if (flags & MYSQL_START_TRANS_OPT_READ_ONLY)
165 thd->tx_read_only=
true;
166 else if (flags & MYSQL_START_TRANS_OPT_READ_WRITE)
174 const bool user_is_super=
175 test(thd->security_ctx->master_access & SUPER_ACL);
176 if (opt_readonly && !user_is_super)
178 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
"--read-only");
181 thd->tx_read_only=
false;
184 thd->variables.option_bits|= OPTION_BEGIN;
185 thd->server_status|= SERVER_STATUS_IN_TRANS;
186 if (thd->tx_read_only)
187 thd->server_status|= SERVER_STATUS_IN_TRANS_READONLY;
188 DBUG_PRINT(
"info", (
"setting SERVER_STATUS_IN_TRANS"));
191 if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
192 res= ha_start_consistent_snapshot(thd);
194 DBUG_RETURN(
test(res));
207 bool trans_commit(THD *thd)
210 DBUG_ENTER(
"trans_commit");
213 char buf1[256], buf2[256];
214 DBUG_PRINT(
"enter", (
"stmt.ha_list: %s, all.ha_list: %s",
215 ha_list_names(thd->transaction.stmt.ha_list, buf1),
216 ha_list_names(thd->transaction.all.ha_list, buf2)));
218 thd->transaction.stmt.dbug_unsafe_rollback_flags(
"stmt");
219 thd->transaction.all.dbug_unsafe_rollback_flags(
"all");
222 if (trans_check_state(thd))
226 ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
227 DBUG_PRINT(
"info", (
"clearing SERVER_STATUS_IN_TRANS"));
229 thd->variables.option_bits&= ~OPTION_BEGIN;
230 thd->transaction.all.reset_unsafe_rollback_flags();
231 thd->lex->start_transaction_opt= 0;
233 DBUG_RETURN(
test(res));
248 bool trans_commit_implicit(THD *thd)
251 DBUG_ENTER(
"trans_commit_implicit");
254 char buf1[256], buf2[256];
255 DBUG_PRINT(
"enter", (
"stmt.ha_list: %s, all.ha_list: %s",
256 ha_list_names(thd->transaction.stmt.ha_list, buf1),
257 ha_list_names(thd->transaction.all.ha_list, buf2)));
259 thd->transaction.stmt.dbug_unsafe_rollback_flags(
"stmt");
260 thd->transaction.all.dbug_unsafe_rollback_flags(
"all");
268 DBUG_ASSERT(thd->transaction.stmt.is_empty() &&
270 thd->transaction.xid_state.xa_state == XA_NOTR);
272 if (thd->in_multi_stmt_transaction_mode() ||
273 (thd->variables.option_bits & OPTION_TABLE_LOCK))
276 if (!thd->locked_tables_mode)
277 thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
279 ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
280 DBUG_PRINT(
"info", (
"clearing SERVER_STATUS_IN_TRANS"));
284 tc_log->
commit(thd,
true);
286 thd->variables.option_bits&= ~OPTION_BEGIN;
287 thd->transaction.all.reset_unsafe_rollback_flags();
295 thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
296 thd->tx_read_only= thd->variables.tx_read_only;
311 bool trans_rollback(THD *thd)
314 DBUG_ENTER(
"trans_rollback");
317 char buf1[256], buf2[256];
318 DBUG_PRINT(
"enter", (
"stmt.ha_list: %s, all.ha_list: %s",
319 ha_list_names(thd->transaction.stmt.ha_list, buf1),
320 ha_list_names(thd->transaction.all.ha_list, buf2)));
322 thd->transaction.stmt.dbug_unsafe_rollback_flags(
"stmt");
323 thd->transaction.all.dbug_unsafe_rollback_flags(
"all");
326 if (trans_check_state(thd))
330 ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
331 DBUG_PRINT(
"info", (
"clearing SERVER_STATUS_IN_TRANS"));
332 res= ha_rollback_trans(thd, TRUE);
333 thd->variables.option_bits&= ~OPTION_BEGIN;
334 thd->transaction.all.reset_unsafe_rollback_flags();
335 thd->lex->start_transaction_opt= 0;
337 DBUG_RETURN(
test(res));
356 bool trans_rollback_implicit(THD *thd)
359 DBUG_ENTER(
"trans_rollback_implict");
367 DBUG_ASSERT(thd->transaction.stmt.is_empty() && !thd->in_sub_stmt);
370 ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
371 DBUG_PRINT(
"info", (
"clearing SERVER_STATUS_IN_TRANS"));
372 res= ha_rollback_trans(thd,
true);
378 thd->transaction.all.reset_unsafe_rollback_flags();
381 DBUG_ASSERT(! thd->transaction_rollback_request);
383 DBUG_RETURN(
test(res));
402 bool trans_commit_stmt(THD *thd)
404 DBUG_ENTER(
"trans_commit_stmt");
406 char buf1[256], buf2[256];
407 DBUG_PRINT(
"enter", (
"stmt.ha_list: %s, all.ha_list: %s",
408 ha_list_names(thd->transaction.stmt.ha_list, buf1),
409 ha_list_names(thd->transaction.all.ha_list, buf2)));
419 DBUG_ASSERT(! thd->in_sub_stmt);
422 DBUG_PRINT(
"enter", (
"stmt.ha_list: %s, all.ha_list: %s",
423 ha_list_names(thd->transaction.stmt.ha_list, buf1),
424 ha_list_names(thd->transaction.all.ha_list, buf2)));
426 thd->transaction.stmt.dbug_unsafe_rollback_flags(
"stmt");
427 thd->transaction.all.dbug_unsafe_rollback_flags(
"all");
430 thd->transaction.merge_unsafe_rollback_flags();
432 if (thd->transaction.stmt.ha_list)
435 if (! thd->in_active_multi_stmt_transaction())
437 thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
438 thd->tx_read_only= thd->variables.tx_read_only;
442 tc_log->
commit(thd,
false);
444 thd->transaction.stmt.reset();
446 DBUG_RETURN(
test(res));
458 bool trans_rollback_stmt(THD *thd)
460 DBUG_ENTER(
"trans_rollback_stmt");
468 DBUG_ASSERT(! thd->in_sub_stmt);
471 char buf1[256], buf2[256];
472 DBUG_PRINT(
"enter", (
"stmt.ha_list: %s, all.ha_list: %s",
473 ha_list_names(thd->transaction.stmt.ha_list, buf1),
474 ha_list_names(thd->transaction.all.ha_list, buf2)));
476 thd->transaction.stmt.dbug_unsafe_rollback_flags(
"stmt");
477 thd->transaction.all.dbug_unsafe_rollback_flags(
"all");
480 thd->transaction.merge_unsafe_rollback_flags();
482 if (thd->transaction.stmt.ha_list)
484 ha_rollback_trans(thd, FALSE);
485 if (! thd->in_active_multi_stmt_transaction())
487 thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
488 thd->tx_read_only= thd->variables.tx_read_only;
494 thd->transaction.stmt.reset();
503 SAVEPOINT **sv= &thd->transaction.savepoints;
507 if (my_strnncoll(system_charset_info, (uchar *) name.str, name.length,
508 (uchar *) (*sv)->name, (*sv)->length) == 0)
527 bool trans_savepoint(THD *thd,
LEX_STRING name)
529 SAVEPOINT **sv, *newsv;
530 DBUG_ENTER(
"trans_savepoint");
532 if (!(thd->in_multi_stmt_transaction_mode() || thd->in_sub_stmt) ||
533 !opt_using_transactions)
536 enum xa_states xa_state= thd->transaction.xid_state.xa_state;
537 if (xa_state != XA_NOTR && xa_state != XA_ACTIVE)
539 my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
543 sv= find_savepoint(thd, name);
548 ha_release_savepoint(thd, *sv);
551 else if ((newsv= (SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
552 savepoint_alloc_size)) == NULL)
554 my_error(ER_OUT_OF_RESOURCES, MYF(0));
558 newsv->name= strmake_root(&thd->transaction.mem_root, name.str, name.length);
559 newsv->length= name.length;
569 newsv->prev= thd->transaction.savepoints;
570 thd->transaction.savepoints= newsv;
581 newsv->mdl_savepoint= thd->mdl_context.mdl_savepoint();
604 bool trans_rollback_to_savepoint(THD *thd,
LEX_STRING name)
607 SAVEPOINT *sv= *find_savepoint(thd, name);
608 DBUG_ENTER(
"trans_rollback_to_savepoint");
611 char buf1[256], buf2[256];
612 DBUG_PRINT(
"enter", (
"stmt.ha_list: %s, all.ha_list: %s",
613 ha_list_names(thd->transaction.stmt.ha_list, buf1),
614 ha_list_names(thd->transaction.all.ha_list, buf2)));
616 thd->transaction.stmt.dbug_unsafe_rollback_flags(
"stmt");
617 thd->transaction.all.dbug_unsafe_rollback_flags(
"all");
622 my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
"SAVEPOINT", name.str);
626 enum xa_states xa_state= thd->transaction.xid_state.xa_state;
627 if (xa_state != XA_NOTR && xa_state != XA_ACTIVE)
629 my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
633 if (ha_rollback_to_savepoint(thd, sv))
635 else if (thd->transaction.all.cannot_safely_rollback() && !thd->slave_thread)
636 thd->transaction.push_unsafe_rollback_warnings(thd);
638 thd->transaction.savepoints= sv;
646 bool binlog_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin;
647 if (!res && !binlog_on)
648 thd->mdl_context.rollback_to_savepoint(sv->mdl_savepoint);
650 DBUG_RETURN(
test(res));
668 bool trans_release_savepoint(THD *thd,
LEX_STRING name)
671 SAVEPOINT *sv= *find_savepoint(thd, name);
672 DBUG_ENTER(
"trans_release_savepoint");
676 my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
"SAVEPOINT", name.str);
680 enum xa_states xa_state= thd->transaction.xid_state.xa_state;
681 if (xa_state != XA_NOTR && xa_state != XA_ACTIVE)
683 my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
687 if (ha_release_savepoint(thd, sv))
690 thd->transaction.savepoints= sv->prev;
692 DBUG_RETURN(
test(res));
705 bool trans_xa_start(THD *thd)
707 enum xa_states xa_state= thd->transaction.xid_state.xa_state;
708 DBUG_ENTER(
"trans_xa_start");
710 if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
712 bool not_equal= !thd->transaction.xid_state.xid.eq(thd->lex->xid);
714 my_error(ER_XAER_NOTA, MYF(0));
716 thd->transaction.xid_state.xa_state= XA_ACTIVE;
717 DBUG_RETURN(not_equal);
721 if (thd->lex->xa_opt != XA_NONE)
722 my_error(ER_XAER_INVAL, MYF(0));
723 else if (xa_state != XA_NOTR)
724 my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
725 else if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction())
726 my_error(ER_XAER_OUTSIDE, MYF(0));
727 else if (!trans_begin(thd))
729 DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
730 thd->transaction.xid_state.xa_state= XA_ACTIVE;
731 thd->transaction.xid_state.rm_error= 0;
732 thd->transaction.xid_state.xid.set(thd->lex->xid);
733 if (xid_cache_insert(&thd->transaction.xid_state))
735 thd->transaction.xid_state.xa_state= XA_NOTR;
736 thd->transaction.xid_state.xid.null();
756 bool trans_xa_end(THD *thd)
758 DBUG_ENTER(
"trans_xa_end");
761 if (thd->lex->xa_opt != XA_NONE)
762 my_error(ER_XAER_INVAL, MYF(0));
763 else if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
764 my_error(ER_XAER_RMFAIL, MYF(0),
765 xa_state_names[thd->transaction.xid_state.xa_state]);
766 else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
767 my_error(ER_XAER_NOTA, MYF(0));
768 else if (!xa_trans_rolled_back(&thd->transaction.xid_state))
769 thd->transaction.xid_state.xa_state= XA_IDLE;
771 DBUG_RETURN(thd->is_error() ||
772 thd->transaction.xid_state.xa_state != XA_IDLE);
785 bool trans_xa_prepare(THD *thd)
787 DBUG_ENTER(
"trans_xa_prepare");
789 if (thd->transaction.xid_state.xa_state != XA_IDLE)
790 my_error(ER_XAER_RMFAIL, MYF(0),
791 xa_state_names[thd->transaction.xid_state.xa_state]);
792 else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
793 my_error(ER_XAER_NOTA, MYF(0));
796 xid_cache_delete(&thd->transaction.xid_state);
797 thd->transaction.xid_state.xa_state= XA_NOTR;
798 my_error(ER_XA_RBROLLBACK, MYF(0));
801 thd->transaction.xid_state.xa_state= XA_PREPARED;
803 DBUG_RETURN(thd->is_error() ||
804 thd->transaction.xid_state.xa_state != XA_PREPARED);
817 bool trans_xa_commit(THD *thd)
820 enum xa_states xa_state= thd->transaction.xid_state.xa_state;
821 DBUG_ENTER(
"trans_xa_commit");
823 if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
835 XID_STATE *xs= xid_cache_search(thd->lex->xid);
836 res= !xs || xs->in_thd;
838 my_error(ER_XAER_NOTA, MYF(0));
841 res= xa_trans_rolled_back(xs);
842 ha_commit_or_rollback_by_xid(thd, thd->lex->xid, !res);
843 xid_cache_delete(xs);
848 if (xa_trans_rolled_back(&thd->transaction.xid_state))
850 xa_trans_force_rollback(thd);
851 res= thd->is_error();
853 else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
857 my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
859 else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
870 mdl_request.
init(MDL_key::COMMIT,
"",
"", MDL_INTENTION_EXCLUSIVE,
873 if (thd->mdl_context.acquire_lock(&mdl_request,
874 thd->variables.lock_wait_timeout))
876 ha_rollback_trans(thd, TRUE);
877 my_error(ER_XAER_RMERR, MYF(0));
881 DEBUG_SYNC(thd,
"trans_xa_commit_after_acquire_commit_lock");
889 my_error(ER_XAER_RMERR, MYF(0));
894 my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
898 thd->variables.option_bits&= ~OPTION_BEGIN;
899 thd->transaction.all.reset_unsafe_rollback_flags();
901 ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
902 DBUG_PRINT(
"info", (
"clearing SERVER_STATUS_IN_TRANS"));
903 xid_cache_delete(&thd->transaction.xid_state);
904 thd->transaction.xid_state.xa_state= XA_NOTR;
919 bool trans_xa_rollback(THD *thd)
922 enum xa_states xa_state= thd->transaction.xid_state.xa_state;
923 DBUG_ENTER(
"trans_xa_rollback");
925 if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
927 XID_STATE *xs= xid_cache_search(thd->lex->xid);
928 if (!xs || xs->in_thd)
929 my_error(ER_XAER_NOTA, MYF(0));
932 xa_trans_rolled_back(xs);
933 ha_commit_or_rollback_by_xid(thd, thd->lex->xid, 0);
934 xid_cache_delete(xs);
936 DBUG_RETURN(thd->get_stmt_da()->is_error());
939 if (xa_state != XA_IDLE && xa_state != XA_PREPARED && xa_state != XA_ROLLBACK_ONLY)
941 my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
945 res= xa_trans_force_rollback(thd);
947 thd->variables.option_bits&= ~OPTION_BEGIN;
948 thd->transaction.all.reset_unsafe_rollback_flags();
950 ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
951 DBUG_PRINT(
"info", (
"clearing SERVER_STATUS_IN_TRANS"));
952 xid_cache_delete(&thd->transaction.xid_state);
953 thd->transaction.xid_state.xa_state= XA_NOTR;