diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_ndbcluster_binlog.cc | 8 | ||||
-rw-r--r-- | sql/handler.cc | 12 | ||||
-rw-r--r-- | sql/log_event.cc | 12 | ||||
-rw-r--r-- | sql/log_event_old.cc | 5 | ||||
-rw-r--r-- | sql/rpl_rli.cc | 11 | ||||
-rw-r--r-- | sql/sp_head.cc | 34 | ||||
-rw-r--r-- | sql/sql_admin.cc | 16 | ||||
-rw-r--r-- | sql/sql_base.cc | 38 | ||||
-rw-r--r-- | sql/sql_base.h | 6 | ||||
-rw-r--r-- | sql/sql_cache.cc | 9 | ||||
-rw-r--r-- | sql/sql_handler.cc | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 39 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 19 | ||||
-rw-r--r-- | sql/sql_table.cc | 28 | ||||
-rw-r--r-- | sql/transaction.cc | 45 | ||||
-rw-r--r-- | sql/transaction.h | 1 |
16 files changed, 229 insertions, 57 deletions
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 48edca0a705..15e0b068826 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2422,6 +2422,12 @@ add_ndb_binlog_index_err: thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); + /* + There should be no need for rolling back transaction due to deadlock + (since ndb_binlog_index is non transactional). + */ + DBUG_ASSERT(! thd->transaction_rollback_request); + thd->mdl_context.release_transactional_locks(); ndb_binlog_index= 0; thd->variables.option_bits= saved_options; diff --git a/sql/handler.cc b/sql/handler.cc index 98d6e8fb103..c3ad1cade99 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1480,10 +1480,16 @@ int ha_rollback_trans(THD *thd, bool all) } trans->ha_list= 0; trans->no_2pc=0; - if (is_real_trans && thd->transaction_rollback_request && - thd->transaction.xid_state.xa_state != XA_NOTR) - thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno(); } + + /* + Thanks to possibility of MDL deadlock rollback request can come even if + transaction hasn't been started in any transactional storage engine. + */ + if (is_real_trans && thd->transaction_rollback_request && + thd->transaction.xid_state.xa_state != XA_NOTR) + thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno(); + /* Always cleanup. Even if nht==0. There may be savepoints. */ if (is_real_trans) thd->transaction.cleanup(); diff --git a/sql/log_event.cc b/sql/log_event.cc index d2682a3eb9e..31ee950dbe4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5104,6 +5104,8 @@ error: thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); /* + - If transaction rollback was requested due to deadlock + perform it and release metadata locks. - If inside a multi-statement transaction, defer the release of metadata locks until the current transaction is either committed or rolled back. This prevents @@ -5113,7 +5115,12 @@ error: - If in autocommit mode, or outside a transactional context, automatically release metadata locks of the current statement. */ - if (! thd->in_multi_stmt_transaction_mode()) + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_multi_stmt_transaction_mode()) thd->mdl_context.release_transactional_locks(); else thd->mdl_context.release_statement_locks(); @@ -8197,7 +8204,10 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd) Xid_log_event will come next which will, if some transactional engines are involved, commit the transaction and flush the pending event to the binlog. + If there was a deadlock the transaction should have been rolled back + already. So there should be no need to rollback the transaction. */ + DBUG_ASSERT(! thd->transaction_rollback_request); error|= (error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd)); /* diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 55d8d72ec5d..1462b08e993 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1808,7 +1808,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) Xid_log_event will come next which will, if some transactional engines are involved, commit the transaction and flush the pending event to the binlog. + If there was a deadlock the transaction should have been rolled back + already. So there should be no need to rollback the transaction. */ + DBUG_ASSERT(! thd->transaction_rollback_request); if ((error= (binlog_error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd)))) rli->report(ERROR_LEVEL, error, "Error in %s event: commit of row events failed, " diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 2d302011b44..e4f2e4fd382 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1317,6 +1317,8 @@ void Relay_log_info::slave_close_thread_tables(THD *thd) close_thread_tables(thd); /* + - If transaction rollback was requested due to deadlock + perform it and release metadata locks. - If inside a multi-statement transaction, defer the release of metadata locks until the current transaction is either committed or rolled back. This prevents @@ -1326,7 +1328,12 @@ void Relay_log_info::slave_close_thread_tables(THD *thd) - If in autocommit mode, or outside a transactional context, automatically release metadata locks of the current statement. */ - if (! thd->in_multi_stmt_transaction_mode()) + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_multi_stmt_transaction_mode()) thd->mdl_context.release_transactional_locks(); else thd->mdl_context.release_statement_locks(); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 552a44c7a96..13d1b310599 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2155,10 +2155,18 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) close_thread_tables(thd); thd_proc_info(thd, 0); - if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) - thd->mdl_context.release_transactional_locks(); - else if (! thd->in_sub_stmt) - thd->mdl_context.release_statement_locks(); + if (! thd->in_sub_stmt) + { + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); + else + thd->mdl_context.release_statement_locks(); + } thd->rollback_item_tree_changes(); @@ -3008,10 +3016,18 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, close_thread_tables(thd); thd_proc_info(thd, 0); - if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) - thd->mdl_context.release_transactional_locks(); - else if (! thd->in_sub_stmt) - thd->mdl_context.release_statement_locks(); + if (! thd->in_sub_stmt) + { + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); + else + thd->mdl_context.release_statement_locks(); + } } if (m_lex->query_tables_own_last) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 16fcf120128..f07a8089853 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -859,8 +859,20 @@ send_result_message: } } /* Error path, a admin command failed. */ - trans_commit_stmt(thd); - trans_commit_implicit(thd); + if (thd->transaction_rollback_request) + { + /* + Unlikely, but transaction rollback was requested by one of storage + engines (e.g. due to deadlock). Perform it. + */ + if (trans_rollback_stmt(thd) || trans_rollback_implicit(thd)) + goto err; + } + else + { + if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) + goto err; + } close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a8279ec0347..040c0425577 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3941,7 +3941,8 @@ end_unlock: /** Open_table_context */ Open_table_context::Open_table_context(THD *thd, uint flags) - :m_failed_table(NULL), + :m_thd(thd), + m_failed_table(NULL), m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()), m_timeout(flags & MYSQL_LOCK_IGNORE_TIMEOUT ? LONG_TIMEOUT : thd->variables.lock_wait_timeout), @@ -4018,6 +4019,7 @@ request_backoff_action(enum_open_table_action action_arg, if (action_arg != OT_REOPEN_TABLES && m_has_locks) { my_error(ER_LOCK_DEADLOCK, MYF(0)); + mark_transaction_to_rollback(m_thd, true); return TRUE; } /* @@ -4027,7 +4029,7 @@ request_backoff_action(enum_open_table_action action_arg, if (table) { DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR); - m_failed_table= (TABLE_LIST*) current_thd->alloc(sizeof(TABLE_LIST)); + m_failed_table= (TABLE_LIST*) m_thd->alloc(sizeof(TABLE_LIST)); if (m_failed_table == NULL) return TRUE; m_failed_table->init_one_table(table->db, table->db_length, @@ -4044,8 +4046,6 @@ request_backoff_action(enum_open_table_action action_arg, /** Recover from failed attempt of open table by performing requested action. - @param thd Thread context - @pre This function should be called only with "action" != OT_NO_ACTION and after having called @sa close_tables_for_reopen(). @@ -4055,7 +4055,7 @@ request_backoff_action(enum_open_table_action action_arg, bool Open_table_context:: -recover_from_failed_open(THD *thd) +recover_from_failed_open() { bool result= FALSE; /* Execute the action. */ @@ -4067,33 +4067,33 @@ recover_from_failed_open(THD *thd) break; case OT_DISCOVER: { - if ((result= lock_table_names(thd, m_failed_table, NULL, + if ((result= lock_table_names(m_thd, m_failed_table, NULL, get_timeout(), MYSQL_OPEN_SKIP_TEMPORARY))) break; - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db, + tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db, m_failed_table->table_name, FALSE); - ha_create_table_from_engine(thd, m_failed_table->db, + ha_create_table_from_engine(m_thd, m_failed_table->db, m_failed_table->table_name); - thd->warning_info->clear_warning_info(thd->query_id); - thd->clear_error(); // Clear error message - thd->mdl_context.release_transactional_locks(); + m_thd->warning_info->clear_warning_info(m_thd->query_id); + m_thd->clear_error(); // Clear error message + m_thd->mdl_context.release_transactional_locks(); break; } case OT_REPAIR: { - if ((result= lock_table_names(thd, m_failed_table, NULL, + if ((result= lock_table_names(m_thd, m_failed_table, NULL, get_timeout(), MYSQL_OPEN_SKIP_TEMPORARY))) break; - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db, + tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db, m_failed_table->table_name, FALSE); - result= auto_repair_table(thd, m_failed_table); - thd->mdl_context.release_transactional_locks(); + result= auto_repair_table(m_thd, m_failed_table); + m_thd->mdl_context.release_transactional_locks(); break; } default: @@ -4926,7 +4926,7 @@ restart: TABLE_LIST element. Altough currently this assumption is valid it may change in future. */ - if (ot_ctx.recover_from_failed_open(thd)) + if (ot_ctx.recover_from_failed_open()) goto err; error= FALSE; @@ -4979,7 +4979,7 @@ restart: { close_tables_for_reopen(thd, start, ot_ctx.start_of_statement_svp()); - if (ot_ctx.recover_from_failed_open(thd)) + if (ot_ctx.recover_from_failed_open()) goto err; error= FALSE; @@ -5417,7 +5417,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, */ thd->mdl_context.rollback_to_savepoint(ot_ctx.start_of_statement_svp()); table_list->mdl_request.ticket= 0; - if (ot_ctx.recover_from_failed_open(thd)) + if (ot_ctx.recover_from_failed_open()) break; } diff --git a/sql/sql_base.h b/sql/sql_base.h index 96ca569dd1f..b118c93ac28 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -519,7 +519,7 @@ public: }; Open_table_context(THD *thd, uint flags); - bool recover_from_failed_open(THD *thd); + bool recover_from_failed_open(); bool request_backoff_action(enum_open_table_action action_arg, TABLE_LIST *table); @@ -559,6 +559,8 @@ public: } private: + /* THD for which tables are opened. */ + THD *m_thd; /** For OT_DISCOVER and OT_REPAIR actions, the table list element for the table which definition should be re-discovered or which diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 34a61e99007..ca3db3b48c0 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1730,7 +1730,12 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", } else thd->lex->safe_to_cache_query= 0; // Don't try to cache this - /* End the statement transaction potentially started by engine. */ + /* + End the statement transaction potentially started by engine. + Currently our engines do not request rollback from callbacks. + If this is going to change code needs to be reworked. + */ + DBUG_ASSERT(! thd->transaction_rollback_request); trans_rollback_stmt(thd); goto err_unlock; // Parse query } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index e20ee243b79..b179d54eadf 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -589,7 +589,10 @@ retry: /* Always close statement transaction explicitly, so that the engine doesn't have to count locks. + There should be no need to perform transaction + rollback due to deadlock. */ + DBUG_ASSERT(! thd->transaction_rollback_request); trans_rollback_stmt(thd); mysql_ha_close_table(thd, hash_tables); goto retry; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ef3454ec9c9..dac42457a87 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1183,6 +1183,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd, close_thread_tables(thd); thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + if (thd->transaction_rollback_request) + { + /* + Transaction rollback was requested since MDL deadlock was + discovered while trying to open tables. Rollback transaction + in all storage engines including binary log and release all + locks. + */ + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + thd->cleanup_after_query(); break; } @@ -1833,7 +1845,7 @@ err: can free its locks if LOCK TABLES locked some tables before finding that it can't lock a table in its list */ - trans_commit_implicit(thd); + trans_rollback(thd); /* Close tables and release metadata locks. */ close_thread_tables(thd); DBUG_ASSERT(!thd->locked_tables_mode); @@ -1885,6 +1897,13 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt); /* + Each statement or replication event which might produce deadlock + should handle transaction rollback on its own. So by the start of + the next statement transaction rollback request should be fulfilled + already. + */ + DBUG_ASSERT(! thd->transaction_rollback_request || thd->in_sub_stmt); + /* In many cases first table of main SELECT_LEX have special meaning => check that it is first table in global list and relink it first in queries_tables list if it is necessary (we need such relinking only @@ -2070,8 +2089,8 @@ mysql_execute_command(THD *thd) or triggers as all such statements prohibited there. */ DBUG_ASSERT(! thd->in_sub_stmt); - /* Commit or rollback the statement transaction. */ - thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + /* Statement transaction still should not be started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); /* Commit the normal transaction if one is active. */ if (trans_commit_implicit(thd)) goto error; @@ -4503,7 +4522,17 @@ finish: DEBUG_SYNC(thd, "execute_command_after_close_tables"); #endif - if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) + if (! thd->in_sub_stmt && thd->transaction_rollback_request) + { + /* + We are not in sub-statement and transaction rollback was requested by + one of storage engines (e.g. due to deadlock). Rollback transaction in + all storage engines including binary log. + */ + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) { /* No transaction control allowed in sub-statements. */ DBUG_ASSERT(! thd->in_sub_stmt); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index f3deafc6035..74279c5539d 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -113,6 +113,7 @@ When one supplies long data for a placeholder: #include <mysql_com.h> #endif #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL +#include "transaction.h" // trans_rollback_implicit /** A result class used to send cursor rows using the binary protocol. @@ -3297,6 +3298,22 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) close_thread_tables(thd); thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + + /* + Transaction rollback was requested since MDL deadlock was discovered + while trying to open tables. Rollback transaction in all storage + engines including binary log and release all locks. + + Once dynamic SQL is allowed as substatements the below if-statement + has to be adjusted to not do rollback in substatement. + */ + DBUG_ASSERT(! thd->in_sub_stmt); + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + lex_end(lex); cleanup_stmt(); thd->restore_backup_statement(this, &stmt_backup); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ac121572ab2..bfed754a90c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4797,7 +4797,6 @@ mysql_discard_or_import_tablespace(THD *thd, error= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); err: - trans_rollback_stmt(thd); thd->tablespace_op=FALSE; if (error == 0) @@ -7331,6 +7330,12 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, Protocol *protocol= thd->protocol; DBUG_ENTER("mysql_checksum_table"); + /* + CHECKSUM TABLE returns results and rollbacks statement transaction, + so it should not be used in stored function or trigger. + */ + DBUG_ASSERT(! thd->in_sub_stmt); + field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2)); item->maybe_null= 1; field_list.push_back(item= new Item_int("Checksum", (longlong) 1, @@ -7349,7 +7354,6 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, strxmov(table_name, table->db ,".", table->table_name, NullS); t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0); - thd->clear_error(); // these errors shouldn't get client protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); @@ -7358,7 +7362,6 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, { /* Table didn't exist */ protocol->store_null(); - thd->clear_error(); } else { @@ -7443,9 +7446,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, t->file->ha_rnd_end(); } } - thd->clear_error(); - if (! thd->in_sub_stmt) - trans_rollback_stmt(thd); + trans_rollback_stmt(thd); close_thread_tables(thd); /* Don't release metadata locks, this will be done at @@ -7453,6 +7454,21 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, */ table->table=0; // For query cache } + + if (thd->transaction_rollback_request) + { + /* + If transaction rollback was requested we honor it. To do this we + abort statement and return error as not only CHECKSUM TABLE is + rolled back but the whole transaction in which it was used. + */ + thd->protocol->remove_last_row(); + goto err; + } + + /* Hide errors from client. Return NULL for problematic tables instead. */ + thd->clear_error(); + if (protocol->write()) goto err; } diff --git a/sql/transaction.cc b/sql/transaction.cc index 3b0af4db710..4fd6af39135 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -268,6 +268,47 @@ bool trans_rollback(THD *thd) /** + Implicitly rollback the current transaction, typically + after deadlock was discovered. + + @param thd Current thread + + @retval False Success + @retval True Failure + + @note ha_rollback_low() which is indirectly called by this + function will mark XA transaction for rollback by + setting appropriate RM error status if there was + transaction rollback request. +*/ + +bool trans_rollback_implicit(THD *thd) +{ + int res; + DBUG_ENTER("trans_rollback_implict"); + + /* + Always commit/rollback statement transaction before manipulating + with the normal one. + Don't perform rollback in the middle of sub-statement, wait till + its end. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty() && !thd->in_sub_stmt); + + thd->server_status&= ~SERVER_STATUS_IN_TRANS; + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); + res= ha_rollback_trans(thd, true); + thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); + thd->transaction.all.modified_non_trans_table= false; + + /* Rollback should clear transaction_rollback_request flag. */ + DBUG_ASSERT(! thd->transaction_rollback_request); + + DBUG_RETURN(test(res)); +} + + +/** Commit the single statement transaction. @note Note that if the autocommit is on, then the following call @@ -339,8 +380,6 @@ bool trans_rollback_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { ha_rollback_trans(thd, FALSE); - 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; } diff --git a/sql/transaction.h b/sql/transaction.h index e002cd4a9dc..abe7823cf9b 100644 --- a/sql/transaction.h +++ b/sql/transaction.h @@ -30,6 +30,7 @@ bool trans_begin(THD *thd, uint flags= 0); bool trans_commit(THD *thd); bool trans_commit_implicit(THD *thd); bool trans_rollback(THD *thd); +bool trans_rollback_implicit(THD *thd); bool trans_commit_stmt(THD *thd); bool trans_rollback_stmt(THD *thd); |