# At a local mysql-6.0-runtime repository of davi
2690 Davi Arnaut 2008-07-31
WL#4284: Transactional DDL locking
Make transaction management more modular through a new interface.
The overall objective of this change is to provide groundwork
for the design of transactional DDL locking by cleaning up the
transaction high level API to better distinguish operations implicit
and explicit, and single statement transaction from operations on
the normal transaction.
Having a a high-level interface for transaction management provides
a better base for implementing transactional concepts that are not
always tied to storage engines and also makes it easier to interect
with other higher level modules of the server.
added:
sql/transaction.cc
sql/transaction.h
modified:
client/Makefile.am
libmysqld/CMakeLists.txt
libmysqld/Makefile.am
sql/CMakeLists.txt
sql/Makefile.am
sql/backup/be_snapshot.cc
sql/backup/kernel.cc
sql/handler.cc
sql/handler.h
sql/lock.cc
sql/log_event.cc
sql/log_event_old.cc
sql/mysql_priv.h
sql/rpl_injector.cc
sql/rpl_rli.cc
sql/set_var.cc
sql/slave.cc
sql/sql_base.cc
sql/sql_class.cc
sql/sql_do.cc
sql/sql_insert.cc
sql/sql_parse.cc
sql/sql_partition.cc
sql/sql_table.cc
sql/sql_yacc.yy
storage/maria/ha_maria.cc
per-file messages:
client/Makefile.am
Add new file to the build.
libmysqld/CMakeLists.txt
Add new file to the build.
libmysqld/Makefile.am
Add new file to the build.
sql/CMakeLists.txt
Add new file to the build.
sql/Makefile.am
Add new file to the build.
sql/backup/be_snapshot.cc
Rename transaction management functions to the new names.
sql/backup/kernel.cc
Rename transaction management functions to the new names.
sql/handler.cc
Remove multiplexer commit or rollback function. Most callers already
have enough information to decided whether to rollback or commit.
Having plain and well named functions makes it easier to read
and understand code.
sql/handler.h
Remove wrapper function as the low level transaction functions
shouldn't be called directly anymore.
sql/lock.cc
Rename transaction management functions to the new names.
sql/log_event.cc
Rename transaction management functions to the new names.
sql/log_event_old.cc
Rename transaction management functions to the new names.
sql/mysql_priv.h
Remove obsolete functions for implicit and explicit commit.
sql/rpl_injector.cc
Rename transaction management functions to the new names.
sql/rpl_rli.cc
Rename transaction management functions to the new names.
sql/set_var.cc
Rename transaction management functions to the new names.
sql/slave.cc
Rename transaction management functions to the new names.
sql/sql_base.cc
Rename transaction management functions to the new names.
sql/sql_class.cc
Rename transaction management functions to the new names.
sql/sql_do.cc
Rename transaction management functions to the new names.
sql/sql_insert.cc
Rename transaction management functions to the new names.
sql/sql_parse.cc
Move transaction management functions to it's own file.
sql/sql_partition.cc
Rename transaction management functions to the new names.
sql/sql_table.cc
Rename transaction management functions to the new names.
sql/sql_yacc.yy
Add header as function indirectly calls transaction functions.
sql/transaction.cc
Implement wrapper functions to differentiate operations on
the single statement transaction from the ones operating
on the normal transaction.
sql/transaction.h
Export new functions for dealing with transaction commands.
storage/maria/ha_maria.cc
Rename transaction management functions to the new names.
=== modified file 'client/Makefile.am'
--- a/client/Makefile.am 2008-06-20 11:40:01 +0000
+++ b/client/Makefile.am 2008-07-31 20:31:54 +0000
@@ -105,7 +105,8 @@ DEFS = -DUNDEF_THREADS_HACK \
sql_src=log_event.h mysql_priv.h rpl_constants.h \
log_event.cc my_decimal.h my_decimal.cc \
log_event_old.h log_event_old.cc \
- rpl_record_old.h rpl_record_old.cc
+ rpl_record_old.h rpl_record_old.cc \
+ transaction.h
strings_src=decimal.c dtoa.c
link_sources:
=== modified file 'libmysqld/CMakeLists.txt'
--- a/libmysqld/CMakeLists.txt 2008-07-09 07:12:43 +0000
+++ b/libmysqld/CMakeLists.txt 2008-07-31 20:31:54 +0000
@@ -203,6 +203,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libm
../sql/scheduler.cc ../sql/sql_audit.cc
../sql/ddl_blocker.cc ../sql/si_objects.cc
../sql/event_parse_data.cc ../sql/mdl.cc
+ ../sql/transaction.cc
${GEN_SOURCES}
${LIB_SOURCES})
=== modified file 'libmysqld/Makefile.am'
--- a/libmysqld/Makefile.am 2008-07-09 07:12:43 +0000
+++ b/libmysqld/Makefile.am 2008-07-31 20:31:54 +0000
@@ -78,8 +78,7 @@ sqlsources = derror.cc field.cc field_co
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
- debug_sync.cc \
- sql_tablespace.cc \
+ debug_sync.cc sql_tablespace.cc transaction.cc \
rpl_injector.cc my_user.c partition_info.cc \
sql_servers.cc ddl_blocker.cc si_objects.cc sql_audit.cc \
event_parse_data.cc mdl.cc
=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt 2008-07-09 07:12:43 +0000
+++ b/sql/CMakeLists.txt 2008-07-31 20:31:54 +0000
@@ -75,7 +75,7 @@ ADD_EXECUTABLE(mysqld
sql_tablespace.cc events.cc ../sql-common/my_user.c
partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
rpl_rli.cc rpl_mi.cc sql_servers.cc sql_audit.cc
- sql_connect.cc scheduler.cc
+ sql_connect.cc scheduler.cc transaction.cc
ddl_blocker.cc si_objects.cc
sql_profile.cc event_parse_data.cc mdl.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
=== modified file 'sql/Makefile.am'
--- a/sql/Makefile.am 2008-07-09 07:12:43 +0000
+++ b/sql/Makefile.am 2008-07-31 20:31:54 +0000
@@ -87,7 +87,7 @@ noinst_HEADERS = item.h item_func.h item
sql_plugin.h authors.h event_parse_data.h \
event_data_objects.h event_scheduler.h \
sql_partition.h partition_info.h partition_element.h \
- probes.h sql_audit.h \
+ probes.h sql_audit.h transaction.h \
contributors.h sql_servers.h ddl_blocker.h \
si_objects.h sql_plist.h mdl.h
@@ -136,7 +136,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.
sql_builtin.cc sql_tablespace.cc partition_info.cc \
sql_servers.cc sql_audit.cc sha2.cc \
ddl_blocker.cc si_objects.cc event_parse_data.cc \
- mdl.cc
+ mdl.cc transaction.cc
if HAVE_DTRACE
mysqld_SOURCES += probes.d
=== modified file 'sql/backup/be_snapshot.cc'
--- a/sql/backup/be_snapshot.cc 2008-07-07 12:51:56 +0000
+++ b/sql/backup/be_snapshot.cc 2008-07-31 20:31:54 +0000
@@ -44,6 +44,7 @@
#include "backup_engine.h"
#include "be_snapshot.h"
#include "backup_aux.h"
+#include "transaction.h"
namespace snapshot_backup {
@@ -72,8 +73,8 @@ result_t Backup::cleanup()
locking_thd->lock_state= LOCK_DONE; // set lock done so destructor won't wait
if (m_trans_start)
{
- ha_autocommit_or_rollback(locking_thd->m_thd, 0);
- end_active_trans(locking_thd->m_thd);
+ trans_commit_stmt(locking_thd->m_thd);
+ trans_commit_implicit(locking_thd->m_thd);
m_trans_start= FALSE;
}
if (tables_open)
@@ -104,7 +105,7 @@ result_t Backup::lock()
locking_thd->m_thd->lex->sql_command= SQLCOM_SELECT;
locking_thd->m_thd->lex->start_transaction_opt|=
MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT;
- int res= begin_trans(locking_thd->m_thd);
+ int res= trans_begin(locking_thd->m_thd);
if (res)
DBUG_RETURN(ERROR);
m_trans_start= TRUE;
=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc 2008-07-19 03:03:39 +0000
+++ b/sql/backup/kernel.cc 2008-07-31 20:31:54 +0000
@@ -75,6 +75,7 @@
#include "be_nodata.h"
#include "ddl_blocker.h"
#include "backup_progress.h"
+#include "transaction.h"
/**
@@ -737,8 +738,8 @@ int Backup_restore_ctx::close()
if (m_thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
{
- ha_autocommit_or_rollback(m_thd, 0);
- end_active_trans(m_thd);
+ trans_commit_stmt(m_thd);
+ trans_commit_implicit(m_thd);
}
// unlock tables if they are still locked
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc 2008-07-25 17:21:55 +0000
+++ b/sql/handler.cc 2008-07-31 20:31:54 +0000
@@ -27,6 +27,7 @@
#include "rpl_filter.h"
#include <myisampack.h>
#include "myisam.h"
+#include "transaction.h"
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
@@ -836,7 +837,7 @@ void ha_close_connection(THD* thd)
do not "register" in thd->transaction lists, and thus do not
modify the transaction state. Besides, each DDL in
MySQL is prefixed with an implicit normal transaction commit
- (a call to end_active_trans()), and thus leaves nothing
+ (a call to trans_commit_implicit()), and thus leaves nothing
to modify.
However, as it has been pointed out with CREATE TABLE .. SELECT,
some DDL statements can start a *new* transaction.
@@ -1277,42 +1278,6 @@ int ha_rollback_trans(THD *thd, bool all
DBUG_RETURN(error);
}
-/**
- This is used to commit or rollback a single statement depending on
- the value of error.
-
- @note
- Note that if the autocommit is on, then the following call inside
- InnoDB will commit or rollback the whole transaction (= the statement). The
- autocommit mechanism built into InnoDB is based on counting locks, but if
- the user has used LOCK TABLES then that mechanism does not know to do the
- commit.
-*/
-int ha_autocommit_or_rollback(THD *thd, int error)
-{
- DBUG_ENTER("ha_autocommit_or_rollback");
-
- if (thd->transaction.stmt.ha_list)
- {
- if (!error)
- {
- if (ha_commit_trans(thd, 0))
- error=1;
- }
- else
- {
- (void) ha_rollback_trans(thd, 0);
- if (thd->transaction_rollback_request && !thd->in_sub_stmt)
- (void) ha_rollback(thd);
- }
-
- thd->variables.tx_isolation=thd->session_tx_isolation;
- }
-
- DBUG_RETURN(error);
-}
-
-
struct xahton_st {
XID *xid;
int result;
@@ -3377,7 +3342,7 @@ int ha_enable_transaction(THD *thd, bool
So, let's commit an open transaction (if any) now.
*/
if (!(error= ha_commit_trans(thd, 0)))
- error= end_trans(thd, COMMIT);
+ error= trans_commit_implicit(thd);
}
DBUG_RETURN(error);
}
=== modified file 'sql/handler.h'
--- a/sql/handler.h 2008-07-11 16:22:44 +0000
+++ b/sql/handler.h 2008-07-31 20:31:54 +0000
@@ -289,9 +289,6 @@ typedef Bitmap<HA_MAX_ALTER_FLAGS> HA_AL
#define HA_CACHE_TBL_ASKTRANSACT 2
#define HA_CACHE_TBL_TRANSACT 4
-/* Options of START TRANSACTION statement (and later of SET TRANSACTION stmt) */
-#define MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT 1
-
/* Flags for method is_fatal_error */
#define HA_CHECK_DUP_KEY 1
#define HA_CHECK_DUP_UNIQUE 2
@@ -2403,10 +2400,6 @@ extern TYPELIB tx_isolation_typelib;
extern TYPELIB myisam_stats_method_typelib;
extern ulong total_ha, total_ha_2pc;
- /* Wrapper functions */
-#define ha_commit(thd) (ha_commit_trans((thd), TRUE))
-#define ha_rollback(thd) (ha_rollback_trans((thd), TRUE))
-
/* lookups */
handlerton *ha_default_handlerton(THD *thd);
plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name);
@@ -2483,13 +2476,12 @@ int ha_release_temporary_latches(THD *th
int ha_start_consistent_snapshot(THD *thd);
int ha_commit_or_rollback_by_xid(XID *xid, bool commit);
int ha_commit_one_phase(THD *thd, bool all);
+int ha_commit_trans(THD *thd, bool all);
int ha_rollback_trans(THD *thd, bool all);
int ha_prepare(THD *thd);
int ha_recover(HASH *commit_list);
/* transactions: these functions never call handlerton functions directly */
-int ha_commit_trans(THD *thd, bool all);
-int ha_autocommit_or_rollback(THD *thd, int error);
int ha_enable_transaction(THD *thd, bool on);
/* savepoints */
=== modified file 'sql/lock.cc'
--- a/sql/lock.cc 2008-07-09 07:12:43 +0000
+++ b/sql/lock.cc 2008-07-31 20:31:54 +0000
@@ -74,6 +74,7 @@
*/
#include "mysql_priv.h"
+#include "transaction.h"
#include <hash.h>
#include <assert.h>
@@ -1440,7 +1441,7 @@ int try_transactional_lock(THD *thd, TAB
err:
/* We need to explicitly commit if autocommit mode is active. */
- (void) ha_autocommit_or_rollback(thd, 0);
+ trans_commit_stmt(thd);
/* Close the tables. The locks (if taken) persist in the storage engines. */
close_tables_for_reopen(thd, &table_list, FALSE);
thd->in_lock_tables= FALSE;
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2008-07-24 10:00:56 +0000
+++ b/sql/log_event.cc 2008-07-31 20:31:54 +0000
@@ -31,6 +31,7 @@
#include "rpl_filter.h"
#include "rpl_utility.h"
#include "rpl_record.h"
+#include "transaction.h"
#include <my_dir.h>
#endif /* MYSQL_CLIENT */
@@ -4506,7 +4507,7 @@ int Xid_log_event::do_apply_event(Relay_
/* For a slave Xid_log_event is COMMIT */
general_log_print(thd, COM_QUERY,
"COMMIT /* implicit, from Xid_log_event */");
- return end_trans(thd, COMMIT);
+ return trans_commit(thd);
}
Log_event::enum_skip_reason
@@ -6830,7 +6831,7 @@ Rows_log_event::do_update_pos(Relay_log_
are involved, commit the transaction and flush the pending event to the
binlog.
*/
- error= ha_autocommit_or_rollback(thd, 0);
+ error= trans_commit_stmt(thd);
/*
Now what if this is not a transactional engine? we still need to
=== modified file 'sql/log_event_old.cc'
--- a/sql/log_event_old.cc 2008-06-28 11:00:59 +0000
+++ b/sql/log_event_old.cc 2008-07-31 20:31:54 +0000
@@ -6,6 +6,7 @@
#endif
#include "log_event_old.h"
#include "rpl_record_old.h"
+#include "transaction.h"
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -1827,7 +1828,7 @@ Old_rows_log_event::do_update_pos(Relay_
are involved, commit the transaction and flush the pending event to the
binlog.
*/
- error= ha_autocommit_or_rollback(thd, 0);
+ error= trans_commit_stmt(thd);
/*
Now what if this is not a transactional engine? we still need to
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2008-07-26 16:38:20 +0000
+++ b/sql/mysql_priv.h 2008-07-31 20:31:54 +0000
@@ -889,15 +889,6 @@ bool parse_sql(THD *thd,
Parser_state *parser_state,
Object_creation_ctx *creation_ctx);
-enum enum_mysql_completiontype {
- ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
- COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
-};
-
-bool begin_trans(THD *thd);
-bool end_active_trans(THD *thd);
-int end_trans(THD *thd, enum enum_mysql_completiontype completion);
-
Item *negate_expression(THD *thd, Item *expr);
/* log.cc */
=== modified file 'sql/rpl_injector.cc'
--- a/sql/rpl_injector.cc 2008-05-29 15:44:11 +0000
+++ b/sql/rpl_injector.cc 2008-07-31 20:31:54 +0000
@@ -15,6 +15,7 @@
#include "mysql_priv.h"
#include "rpl_injector.h"
+#include "transaction.h"
/*
injector::transaction - member definitions
@@ -36,7 +37,7 @@ injector::transaction::transaction(MYSQL
m_start_pos.m_file_pos= log_info.pos;
m_thd->lex->start_transaction_opt= 0; /* for begin_trans() */
- begin_trans(m_thd);
+ trans_begin(m_thd);
thd->set_current_stmt_binlog_row_based();
}
@@ -82,8 +83,8 @@ int injector::transaction::commit()
is committed by committing the statement transaction
explicitly.
*/
- ha_autocommit_or_rollback(m_thd, 0);
- end_trans(m_thd, COMMIT);
+ trans_commit_stmt(m_thd);
+ trans_commit(m_thd);
DBUG_RETURN(0);
}
=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc 2008-06-28 11:00:59 +0000
+++ b/sql/rpl_rli.cc 2008-07-31 20:31:54 +0000
@@ -20,6 +20,7 @@
#include <my_dir.h> // For MY_STAT
#include "sql_repl.h" // For check_binlog_magic
#include "rpl_utility.h"
+#include "transaction.h"
static int count_relay_log_space(Relay_log_info* rli);
@@ -1162,8 +1163,8 @@ void Relay_log_info::cleanup_context(THD
*/
if (error)
{
- ha_autocommit_or_rollback(thd, 1); // if a "statement transaction"
- end_trans(thd, ROLLBACK); // if a "real transaction"
+ trans_rollback_stmt(thd); // if a "statement transaction"
+ trans_rollback(thd); // if a "real transaction"
}
m_table_map.clear_tables();
slave_close_thread_tables(thd);
=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc 2008-07-25 17:21:55 +0000
+++ b/sql/set_var.cc 2008-07-31 20:31:54 +0000
@@ -61,6 +61,7 @@
#include <my_dir.h>
#include "events.h"
+#include "transaction.h"
/* WITH_NDBCLUSTER_STORAGE_ENGINE */
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
@@ -2979,7 +2980,7 @@ static bool set_option_autocommit(THD *t
*/
if (var->save_result.ulong_value != 0 &&
(thd->options & OPTION_NOT_AUTOCOMMIT) &&
- ha_commit(thd))
+ trans_commit(thd))
return 1;
if (var->save_result.ulong_value != 0)
=== modified file 'sql/slave.cc'
--- a/sql/slave.cc 2008-07-21 03:55:09 +0000
+++ b/sql/slave.cc 2008-07-31 20:31:54 +0000
@@ -34,6 +34,7 @@
#include "sql_repl.h"
#include "rpl_filter.h"
#include "repl_failsafe.h"
+#include "transaction.h"
#include <thr_alarm.h>
#include <my_dir.h>
#include <sql_common.h>
@@ -1953,7 +1954,7 @@ static int exec_relay_log_event(THD* thd
else
{
exec_res= 0;
- end_trans(thd, ROLLBACK);
+ trans_rollback(thd);
/* chance for concurrent connection to get more locks */
safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
(CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2008-07-09 14:27:18 +0000
+++ b/sql/sql_base.cc 2008-07-31 20:31:54 +0000
@@ -21,6 +21,7 @@
#include "sp_head.h"
#include "sp.h"
#include "sql_trigger.h"
+#include "transaction.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
@@ -1355,7 +1356,7 @@ void close_thread_tables(THD *thd,
if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
{
thd->main_da.can_overwrite_status= TRUE;
- ha_autocommit_or_rollback(thd, thd->is_error());
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
thd->main_da.can_overwrite_status= FALSE;
/*
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2008-07-25 17:21:55 +0000
+++ b/sql/sql_class.cc 2008-07-31 20:31:54 +0000
@@ -42,6 +42,7 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
+#include "transaction.h"
/*
The following is used to initialise Table_ident with a internal
@@ -846,7 +847,8 @@ void THD::cleanup(void)
}
#endif
{
- ha_rollback(this);
+ transaction.xid_state.xa_state= XA_NOTR;
+ trans_rollback(this);
xid_cache_delete(&transaction.xid_state);
}
locked_tables_list.unlock_locked_tables(this);
=== modified file 'sql/sql_do.cc'
--- a/sql/sql_do.cc 2008-02-19 12:45:21 +0000
+++ b/sql/sql_do.cc 2008-07-31 20:31:54 +0000
@@ -17,6 +17,7 @@
/* Execute DO statement */
#include "mysql_priv.h"
+#include "transaction.h"
bool mysql_do(THD *thd, List<Item> &values)
{
@@ -36,7 +37,7 @@ bool mysql_do(THD *thd, List<Item> &valu
will clear the error and the rollback in the end of
dispatch_command() won't work.
*/
- ha_autocommit_or_rollback(thd, thd->is_error());
+ trans_rollback_stmt(thd);
thd->clear_error(); // DO always is OK
}
my_ok(thd);
=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc 2008-07-21 03:55:09 +0000
+++ b/sql/sql_insert.cc 2008-07-31 20:31:54 +0000
@@ -62,6 +62,7 @@
#include "slave.h"
#include "rpl_mi.h"
#include "sql_audit.h"
+#include "transaction.h"
#ifndef EMBEDDED_LIBRARY
static bool delayed_get_table(THD *thd, TABLE_LIST *table_list);
@@ -2487,7 +2488,7 @@ pthread_handler_t handle_delayed_insert(
*/
di->table->file->ha_release_auto_increment();
mysql_unlock_tables(thd, lock);
- ha_autocommit_or_rollback(thd, 0);
+ trans_commit_stmt(thd);
di->group_count=0;
mysql_audit_release(thd);
pthread_mutex_lock(&di->mutex);
@@ -2508,7 +2509,7 @@ err:
first call to ha_*_row() instead. Remove code that are used to
cover for the case outlined above.
*/
- ha_autocommit_or_rollback(thd, 1);
+ trans_rollback_stmt(thd);
#ifndef __WIN__
end:
@@ -3746,8 +3747,8 @@ bool select_create::send_eof()
*/
if (!table->s->tmp_table)
{
- ha_autocommit_or_rollback(thd, 0);
- end_active_trans(thd);
+ trans_commit_stmt(thd);
+ trans_commit_implicit(thd);
}
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2008-07-26 16:38:20 +0000
+++ b/sql/sql_parse.cc 2008-07-31 20:31:54 +0000
@@ -29,6 +29,7 @@
#include "sql_trigger.h"
#include <ddl_blocker.h>
#include "sql_audit.h"
+#include "transaction.h"
#ifdef BACKUP_TEST
#include "backup/backup_test.h"
@@ -97,65 +98,6 @@ const char *xa_state_names[]={
extern DDL_blocker_class *DDL_blocker;
-bool end_active_trans(THD *thd)
-{
- int error=0;
- DBUG_ENTER("end_active_trans");
- if (unlikely(thd->in_sub_stmt))
- {
- my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
- DBUG_RETURN(1);
- }
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- DBUG_RETURN(1);
- }
- if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
- OPTION_TABLE_LOCK))
- {
- DBUG_PRINT("info",("options: 0x%llx", thd->options));
- /* Safety if one did "drop table" on locked tables */
- if (!thd->locked_tables_mode)
- thd->options&= ~OPTION_TABLE_LOCK;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (ha_commit(thd))
- error=1;
-#ifdef WITH_MARIA_STORAGE_ENGINE
- ha_maria::implicit_commit(thd, TRUE);
-#endif
- }
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- DBUG_RETURN(error);
-}
-
-
-bool begin_trans(THD *thd)
-{
- int error=0;
- if (unlikely(thd->in_sub_stmt))
- {
- my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
- return 1;
- }
-
- thd->locked_tables_list.unlock_locked_tables(thd);
-
- if (end_active_trans(thd))
- error= -1;
- else
- {
- LEX *lex= thd->lex;
- thd->options|= OPTION_BEGIN;
- thd->server_status|= SERVER_STATUS_IN_TRANS;
- if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
- error= ha_start_consistent_snapshot(thd);
- }
- return error;
-}
-
#ifdef HAVE_REPLICATION
/**
Returns true if all tables should be ignored.
@@ -216,9 +158,9 @@ static bool opt_implicit_commit(THD *thd
if (!skip)
{
/* Commit or rollback the statement transaction. */
- ha_autocommit_or_rollback(thd, thd->is_error());
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
/* Commit the normal transaction if one is active. */
- res= end_active_trans(thd);
+ res= trans_commit_implicit(thd);
}
DBUG_RETURN(res);
@@ -629,81 +571,6 @@ void cleanup_items(Item *item)
DBUG_VOID_RETURN;
}
-/**
- Ends the current transaction and (maybe) begin the next.
-
- @param thd Current thread
- @param completion Completion type
-
- @retval
- 0 OK
-*/
-
-int end_trans(THD *thd, enum enum_mysql_completiontype completion)
-{
- bool do_release= 0;
- int res= 0;
- DBUG_ENTER("end_trans");
-
- if (unlikely(thd->in_sub_stmt))
- {
- my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
- DBUG_RETURN(1);
- }
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- DBUG_RETURN(1);
- }
- thd->lex->start_transaction_opt= 0; /* for begin_trans() */
- switch (completion) {
- case COMMIT:
- /*
- We don't use end_active_trans() here to ensure that this works
- even if there is a problem with the OPTION_AUTO_COMMIT flag
- (Which of course should never happen...)
- */
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- res= ha_commit(thd);
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- break;
- case COMMIT_RELEASE:
- do_release= 1; /* fall through */
- case COMMIT_AND_CHAIN:
- res= end_active_trans(thd);
- if (!res && completion == COMMIT_AND_CHAIN)
- res= begin_trans(thd);
- break;
- case ROLLBACK_RELEASE:
- do_release= 1; /* fall through */
- case ROLLBACK:
- case ROLLBACK_AND_CHAIN:
- {
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (ha_rollback(thd))
- res= -1;
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- if (!res && (completion == ROLLBACK_AND_CHAIN))
- res= begin_trans(thd);
- break;
- }
- default:
- res= -1;
- my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
- DBUG_RETURN(-1);
- }
-
- if (res < 0)
- my_error(thd->killed_errno(), MYF(0));
- else if ((res == 0) && do_release)
- thd->killed= THD::KILL_CONNECTION;
-
- DBUG_RETURN(res);
-}
-
#ifndef EMBEDDED_LIBRARY
/**
@@ -1326,14 +1193,14 @@ bool dispatch_command(enum enum_server_c
bool not_used;
status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
ulong options= (ulong) (uchar) packet[0];
- if (end_active_trans(thd))
+ if (trans_commit_implicit(thd))
break;
if (check_global_access(thd,RELOAD_ACL))
break;
general_log_print(thd, command, NullS);
if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used))
break;
- if (end_active_trans(thd))
+ if (trans_commit_implicit(thd))
break;
my_ok(thd);
break;
@@ -1483,7 +1350,7 @@ bool dispatch_command(enum enum_server_c
/* If commit fails, we should be able to reset the OK status. */
thd->main_da.can_overwrite_status= TRUE;
- ha_autocommit_or_rollback(thd, thd->is_error());
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
thd->main_da.can_overwrite_status= FALSE;
thd->transaction.stmt.reset();
@@ -3349,7 +3216,7 @@ end_with_restore_list:
thd->locked_tables_list.unlock_locked_tables(thd);
if (thd->options & OPTION_TABLE_LOCK)
{
- end_active_trans(thd);
+ trans_commit_implicit(thd);
thd->options&= ~(OPTION_TABLE_LOCK);
}
if (thd->global_read_lock)
@@ -3403,7 +3270,7 @@ end_with_restore_list:
goto error;
thd->locked_tables_list.unlock_locked_tables(thd);
/* we must end the trasaction first, regardless of anything */
- if (end_active_trans(thd))
+ if (trans_commit_implicit(thd))
goto error;
alloc_mdl_locks(all_tables, thd->locked_tables_list.locked_tables_root());
@@ -3426,8 +3293,8 @@ end_with_restore_list:
can free its locks if LOCK TABLES locked some tables before finding
that it can't lock a table in its list
*/
- ha_autocommit_or_rollback(thd, 1);
- end_active_trans(thd);
+ trans_rollback_stmt(thd);
+ trans_commit_implicit(thd);
thd->options&= ~(OPTION_TABLE_LOCK);
}
else
@@ -3916,129 +3783,52 @@ end_with_restore_list:
break;
case SQLCOM_BEGIN:
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
DEBUG_SYNC(thd, "before_begin_trans");
- if (begin_trans(thd))
+ if (trans_begin(thd, lex->start_transaction_opt))
goto error;
my_ok(thd);
break;
case SQLCOM_COMMIT:
DBUG_ASSERT(thd->lock == NULL ||
thd->locked_tables_mode == LTM_LOCK_TABLES);
- if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
- lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
+ if (trans_commit(thd))
+ goto error;
+ /* Begin transaction with the same isolation level. */
+ if (lex->tx_chain && trans_begin(thd))
goto error;
+ /* Disconnect the current client connection. */
+ if (lex->tx_release)
+ thd->killed= THD::KILL_CONNECTION;
DEBUG_SYNC(thd, "after_commit");
my_ok(thd);
break;
case SQLCOM_ROLLBACK:
DBUG_ASSERT(thd->lock == NULL ||
thd->locked_tables_mode == LTM_LOCK_TABLES);
- if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
- lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
+ if (trans_rollback(thd))
+ goto error;
+ /* Begin transaction with the same isolation level. */
+ if (lex->tx_chain && trans_begin(thd))
goto error;
+ /* Disconnect the current client connection. */
+ if (lex->tx_release)
+ thd->killed= THD::KILL_CONNECTION;
my_ok(thd);
break;
case SQLCOM_RELEASE_SAVEPOINT:
- {
- SAVEPOINT *sv;
- for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
- {
- if (my_strnncoll(system_charset_info,
- (uchar *)lex->ident.str, lex->ident.length,
- (uchar *)sv->name, sv->length) == 0)
- break;
- }
- if (sv)
- {
- if (ha_release_savepoint(thd, sv))
- res= TRUE; // cannot happen
- else
- my_ok(thd);
- thd->transaction.savepoints=sv->prev;
- }
- else
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
+ if (trans_release_savepoint(thd, lex->ident))
+ goto error;
+ my_ok(thd);
break;
- }
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
- {
- SAVEPOINT *sv;
- for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
- {
- if (my_strnncoll(system_charset_info,
- (uchar *)lex->ident.str, lex->ident.length,
- (uchar *)sv->name, sv->length) == 0)
- break;
- }
- if (sv)
- {
- if (ha_rollback_to_savepoint(thd, sv))
- res= TRUE; // cannot happen
- else
- {
- if (((thd->options & OPTION_KEEP_LOG) ||
- thd->transaction.all.modified_non_trans_table) &&
- !thd->slave_thread)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARNING_NOT_COMPLETE_ROLLBACK,
- ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
- my_ok(thd);
- }
- thd->transaction.savepoints=sv;
- }
- else
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
+ if (trans_rollback_to_savepoint(thd, lex->ident))
+ goto error;
+ my_ok(thd);
break;
- }
case SQLCOM_SAVEPOINT:
- if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
- thd->in_sub_stmt) || !opt_using_transactions)
- my_ok(thd);
- else
- {
- SAVEPOINT **sv, *newsv;
- for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
- {
- if (my_strnncoll(system_charset_info,
- (uchar *)lex->ident.str, lex->ident.length,
- (uchar *)(*sv)->name, (*sv)->length) == 0)
- break;
- }
- if (*sv) /* old savepoint of the same name exists */
- {
- newsv=*sv;
- ha_release_savepoint(thd, *sv); // it cannot fail
- *sv=(*sv)->prev;
- }
- else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
- savepoint_alloc_size)) == 0)
- {
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
- break;
- }
- newsv->name=strmake_root(&thd->transaction.mem_root,
- lex->ident.str, lex->ident.length);
- newsv->length=lex->ident.length;
- /*
- if we'll get an error here, don't add new savepoint to the list.
- we'll lose a little bit of memory in transaction mem_root, but it'll
- be free'd when transaction ends anyway
- */
- if (ha_savepoint(thd, newsv))
- res= TRUE;
- else
- {
- newsv->prev=thd->transaction.savepoints;
- thd->transaction.savepoints=newsv;
- my_ok(thd);
- }
- }
+ if (trans_savepoint(thd, lex->ident))
+ goto error;
+ my_ok(thd);
break;
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SPFUNCTION:
@@ -4380,7 +4170,7 @@ create_sp_error:
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
goto error;
- if (end_active_trans(thd))
+ if (trans_commit_implicit(thd))
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sp_automatic_privileges && !opt_noacl &&
@@ -4506,173 +4296,29 @@ create_sp_error:
break;
}
case SQLCOM_XA_START:
- if (thd->transaction.xid_state.xa_state == XA_IDLE &&
- thd->lex->xa_opt == XA_RESUME)
- {
- if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- my_error(ER_XAER_NOTA, MYF(0));
- break;
- }
- thd->transaction.xid_state.xa_state=XA_ACTIVE;
- my_ok(thd);
- break;
- }
- if (thd->lex->xa_opt != XA_NONE)
- { // JOIN is not supported yet. TODO
- my_error(ER_XAER_INVAL, MYF(0));
- break;
- }
- if (thd->transaction.xid_state.xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (thd->locked_tables_mode || thd->active_transaction())
- {
- my_error(ER_XAER_OUTSIDE, MYF(0));
- break;
- }
- if (xid_cache_search(thd->lex->xid))
- {
- my_error(ER_XAER_DUPID, MYF(0));
- break;
- }
- DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
- thd->transaction.xid_state.xa_state=XA_ACTIVE;
- thd->transaction.xid_state.xid.set(thd->lex->xid);
- xid_cache_insert(&thd->transaction.xid_state);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
- thd->server_status|= SERVER_STATUS_IN_TRANS;
+ if (trans_xa_start(thd))
+ goto error;
my_ok(thd);
break;
case SQLCOM_XA_END:
- /* fake it */
- if (thd->lex->xa_opt != XA_NONE)
- { // SUSPEND and FOR MIGRATE are not supported yet. TODO
- my_error(ER_XAER_INVAL, MYF(0));
- break;
- }
- if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- my_error(ER_XAER_NOTA, MYF(0));
- break;
- }
- thd->transaction.xid_state.xa_state=XA_IDLE;
+ if (trans_xa_end(thd))
+ goto error;
my_ok(thd);
break;
case SQLCOM_XA_PREPARE:
- if (thd->transaction.xid_state.xa_state != XA_IDLE)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- my_error(ER_XAER_NOTA, MYF(0));
- break;
- }
- if (ha_prepare(thd))
- {
- my_error(ER_XA_RBROLLBACK, MYF(0));
- xid_cache_delete(&thd->transaction.xid_state);
- thd->transaction.xid_state.xa_state=XA_NOTR;
- break;
- }
- thd->transaction.xid_state.xa_state=XA_PREPARED;
+ if (trans_xa_prepare(thd))
+ goto error;
my_ok(thd);
break;
case SQLCOM_XA_COMMIT:
- if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- XID_STATE *xs=xid_cache_search(thd->lex->xid);
- if (!xs || xs->in_thd)
- my_error(ER_XAER_NOTA, MYF(0));
- else
- {
- ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
- xid_cache_delete(xs);
- my_ok(thd);
- }
- break;
- }
- if (thd->transaction.xid_state.xa_state == XA_IDLE &&
- thd->lex->xa_opt == XA_ONE_PHASE)
- {
- int r;
- if ((r= ha_commit(thd)))
- my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
- else
- my_ok(thd);
- }
- else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
- thd->lex->xa_opt == XA_NONE)
- {
- if (wait_if_global_read_lock(thd, 0, 0))
- {
- ha_rollback(thd);
- my_error(ER_XAER_RMERR, MYF(0));
- }
- else
- {
- if (ha_commit_one_phase(thd, 1))
- my_error(ER_XAER_RMERR, MYF(0));
- else
- my_ok(thd);
- start_waiting_global_read_lock(thd);
- }
- }
- else
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- xid_cache_delete(&thd->transaction.xid_state);
- thd->transaction.xid_state.xa_state=XA_NOTR;
+ if (trans_xa_commit(thd))
+ goto error;
+ my_ok(thd);
break;
case SQLCOM_XA_ROLLBACK:
- if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
- {
- XID_STATE *xs=xid_cache_search(thd->lex->xid);
- if (!xs || xs->in_thd)
- my_error(ER_XAER_NOTA, MYF(0));
- else
- {
- ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
- xid_cache_delete(xs);
- my_ok(thd);
- }
- break;
- }
- if (thd->transaction.xid_state.xa_state != XA_IDLE &&
- thd->transaction.xid_state.xa_state != XA_PREPARED)
- {
- my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xid_state.xa_state]);
- break;
- }
- if (ha_rollback(thd))
- my_error(ER_XAER_RMERR, MYF(0));
- else
- my_ok(thd);
- thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- xid_cache_delete(&thd->transaction.xid_state);
- thd->transaction.xid_state.xa_state=XA_NOTR;
+ if (trans_xa_rollback(thd))
+ goto error;
+ my_ok(thd);
break;
case SQLCOM_XA_RECOVER:
res= mysql_xa_recover(thd);
=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc 2008-07-15 16:29:51 +0000
+++ b/sql/sql_partition.cc 2008-07-31 20:31:54 +0000
@@ -37,6 +37,7 @@
#include <errno.h>
#include <m_ctype.h>
#include "my_md5.h"
+#include "transaction.h"
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
@@ -3966,8 +3967,8 @@ static int fast_end_partition(THD *thd,
if (!is_empty)
query_cache_invalidate3(thd, table_list, 0);
- error= ha_autocommit_or_rollback(thd, 0);
- if (end_active_trans(thd))
+ error= trans_commit_stmt(thd);
+ if (trans_commit_implicit(thd))
error= 1;
if (error)
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2008-07-26 16:38:20 +0000
+++ b/sql/sql_table.cc 2008-07-31 20:31:54 +0000
@@ -22,6 +22,7 @@
#include "sp_head.h"
#include "sql_trigger.h"
#include "sql_show.h"
+#include "transaction.h"
#ifdef __WIN__
#include <io.h>
@@ -4217,8 +4218,8 @@ static bool mysql_admin_table(THD* thd,
DBUG_PRINT("admin", ("calling prepare_func"));
switch ((*prepare_func)(thd, table, check_opt)) {
case 1: // error, message written to net
- ha_autocommit_or_rollback(thd, 1);
- end_trans(thd, ROLLBACK);
+ trans_rollback_stmt(thd);
+ trans_rollback(thd);
close_thread_tables(thd);
DBUG_PRINT("admin", ("simple error, admin next table"));
continue;
@@ -4276,8 +4277,8 @@ static bool mysql_admin_table(THD* thd,
length= my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
table_name);
protocol->store(buff, length, system_charset_info);
- ha_autocommit_or_rollback(thd, 0);
- end_trans(thd, COMMIT);
+ trans_commit_stmt(thd);
+ trans_commit(thd);
close_thread_tables(thd);
lex->reset_query_tables_list(FALSE);
table->table=0; // For query cache
@@ -4326,7 +4327,7 @@ static bool mysql_admin_table(THD* thd,
HA_ADMIN_NEEDS_ALTER))
{
DBUG_PRINT("admin", ("recreating table"));
- ha_autocommit_or_rollback(thd, 1);
+ trans_rollback_stmt(thd);
close_thread_tables(thd);
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
result_code= mysql_recreate_table(thd, table);
@@ -4439,7 +4440,7 @@ send_result_message:
"try with alter", so here we close the table, do an ALTER TABLE,
reopen the table and do ha_innobase::analyze() on it.
*/
- ha_autocommit_or_rollback(thd, 0);
+ trans_commit_stmt(thd);
close_thread_tables(thd);
TABLE_LIST *save_next_local= table->next_local,
*save_next_global= table->next_global;
@@ -4455,7 +4456,7 @@ send_result_message:
*/
if (thd->main_da.is_ok())
thd->main_da.reset_diagnostics_area();
- ha_autocommit_or_rollback(thd, 0);
+ trans_commit_stmt(thd);
close_thread_tables(thd);
if (!result_code) // recreation went ok
{
@@ -4544,8 +4545,8 @@ send_result_message:
query_cache_invalidate3(thd, table->table, 0);
}
}
- ha_autocommit_or_rollback(thd, 0);
- end_trans(thd, COMMIT);
+ trans_commit_stmt(thd);
+ trans_commit_implicit(thd);
close_thread_tables(thd);
table->table=0; // For query cache
if (protocol->write())
@@ -4556,8 +4557,8 @@ send_result_message:
DBUG_RETURN(FALSE);
err:
- ha_autocommit_or_rollback(thd, 1);
- end_trans(thd, ROLLBACK);
+ trans_rollback_stmt(thd);
+ trans_rollback(thd);
close_thread_tables(thd); // Shouldn't be needed
if (table)
table->table=0;
@@ -5049,15 +5050,15 @@ mysql_discard_or_import_tablespace(THD *
query_cache_invalidate3(thd, table_list, 0);
/* The ALTER TABLE is always in its own transaction */
- error = ha_autocommit_or_rollback(thd, 0);
- if (end_active_trans(thd))
+ error= trans_commit_stmt(thd);
+ if (trans_commit_implicit(thd))
error=1;
if (error)
goto err;
write_bin_log(thd, FALSE, thd->query, thd->query_length);
err:
- ha_autocommit_or_rollback(thd, error);
+ trans_rollback_stmt(thd);
thd->tablespace_op=FALSE;
if (error == 0)
@@ -5814,8 +5815,8 @@ mysql_fast_or_online_alter_table(THD *th
wait_if_global_read_lock(), which could create a deadlock if called
with LOCK_open.
*/
- error= ha_autocommit_or_rollback(thd, 0);
- if (ha_commit(thd))
+ error= trans_commit_stmt(thd);
+ if (trans_commit_implicit(thd))
error= 1;
if (error)
@@ -6948,8 +6949,8 @@ view_err:
}
else
{
- error= ha_autocommit_or_rollback(thd, 0);
- if (end_active_trans(thd))
+ error= trans_commit_stmt(thd);
+ if (trans_commit_implicit(thd))
error= 1;
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -7394,9 +7395,9 @@ err:
Ensure that the new table is saved properly to disk so that we
can do a rename
*/
- if (ha_autocommit_or_rollback(thd, 0))
+ if (trans_commit_stmt(thd))
error=1;
- if (end_active_trans(thd))
+ if (trans_commit_implicit(thd))
error=1;
thd->variables.sql_mode= save_sql_mode;
=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy 2008-07-25 17:21:55 +0000
+++ b/sql/sql_yacc.yy 2008-07-31 20:31:54 +0000
@@ -44,6 +44,7 @@
#include "sp_rcontext.h"
#include "sp.h"
#include "event_parse_data.h"
+#include "transaction.h"
#include <myisam.h>
#include <myisammrg.h>
=== added file 'sql/transaction.cc'
--- a/sql/transaction.cc 1970-01-01 00:00:00 +0000
+++ b/sql/transaction.cc 2008-07-31 20:31:54 +0000
@@ -0,0 +1,581 @@
+/* Copyright (C) 2008 Sun/MySQL
+
+ 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "transaction.h"
+
+#ifdef WITH_MARIA_STORAGE_ENGINE
+#include "../storage/maria/ha_maria.h"
+#endif
+
+/* Conditions under which the transaction state must not change. */
+static bool trans_check(THD *thd)
+{
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ DBUG_ENTER("trans_check");
+
+ if (unlikely(thd->in_sub_stmt))
+ my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
+ if (xa_state != XA_NOTR)
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ else
+ DBUG_RETURN(FALSE);
+
+ DBUG_RETURN(TRUE);
+}
+
+
+/**
+ Begin a new transaction.
+
+ @note Beginning a transaction implicitly commits any current
+ transaction and releases existing locks.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_begin(THD *thd, uint flags)
+{
+ int res= FALSE;
+ DBUG_ENTER("trans_begin");
+
+ if (trans_check(thd))
+ DBUG_RETURN(TRUE);
+
+ thd->locked_tables_list.unlock_locked_tables(thd);
+
+ if (trans_commit_implicit(thd))
+ DBUG_RETURN(TRUE);
+
+ thd->options|= OPTION_BEGIN;
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+
+ if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
+ res= ha_start_consistent_snapshot(thd);
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Commit the current transaction, making its changes permanent.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_commit(THD *thd)
+{
+ int res;
+ DBUG_ENTER("trans_commit");
+
+ if (trans_check(thd))
+ DBUG_RETURN(TRUE);
+
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= ha_commit_trans(thd, TRUE);
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Implicitly commit the current transaction.
+
+ @note A implicit commit does not releases existing table locks.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_commit_implicit(THD *thd)
+{
+ bool res= FALSE;
+ DBUG_ENTER("trans_commit_implicit");
+
+ if (trans_check(thd))
+ DBUG_RETURN(TRUE);
+
+ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
+ OPTION_TABLE_LOCK))
+ {
+ /* Safety if one did "drop table" on locked tables */
+ if (!thd->locked_tables_mode)
+ thd->options&= ~OPTION_TABLE_LOCK;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= test(ha_commit_trans(thd, TRUE));
+#ifdef WITH_MARIA_STORAGE_ENGINE
+ ha_maria::implicit_commit(thd, TRUE);
+#endif
+ }
+
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Rollback the current transaction, canceling its changes.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_rollback(THD *thd)
+{
+ int res;
+ DBUG_ENTER("trans_rollback");
+
+ if (trans_check(thd))
+ DBUG_RETURN(TRUE);
+
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= ha_rollback_trans(thd, TRUE);
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Commit the single statement transaction.
+
+ @note Note that if the autocommit is on, then the following call
+ inside InnoDB will commit or rollback the whole transaction
+ (= the statement). The autocommit mechanism built into InnoDB
+ is based on counting locks, but if the user has used LOCK
+ TABLES then that mechanism does not know to do the commit.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_commit_stmt(THD *thd)
+{
+ DBUG_ENTER("trans_commit_stmt");
+ int res= FALSE;
+ if (thd->transaction.stmt.ha_list)
+ res= ha_commit_trans(thd, FALSE);
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Rollback the single statement transaction.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+bool trans_rollback_stmt(THD *thd)
+{
+ DBUG_ENTER("trans_rollback_stmt");
+
+ if (thd->transaction.stmt.ha_list)
+ {
+ thd->transaction_rollback_request= FALSE;
+ ha_rollback_trans(thd, FALSE);
+ if (thd->transaction_rollback_request && !thd->in_sub_stmt)
+ ha_rollback_trans(thd, TRUE);
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+/* Find a named savepoint in the current transaction. */
+static SAVEPOINT **
+find_savepoint(THD *thd, LEX_STRING name)
+{
+ SAVEPOINT **sv= &thd->transaction.savepoints;
+
+ while (*sv)
+ {
+ if (my_strnncoll(system_charset_info, (uchar *) name.str, name.length,
+ (uchar *) (*sv)->name, (*sv)->length) == 0)
+ break;
+ sv= &(*sv)->prev;
+ }
+
+ return sv;
+}
+
+
+/**
+ Set a named transaction savepoint.
+
+ @param thd Current thread
+ @param name Savepoint name
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_savepoint(THD *thd, LEX_STRING name)
+{
+ SAVEPOINT **sv, *newsv;
+ DBUG_ENTER("trans_savepoint");
+
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
+ thd->in_sub_stmt) || !opt_using_transactions)
+ DBUG_RETURN(FALSE);
+
+ sv= find_savepoint(thd, name);
+
+ if (*sv) /* old savepoint of the same name exists */
+ {
+ newsv= *sv;
+ ha_release_savepoint(thd, *sv);
+ *sv= (*sv)->prev;
+ }
+ else if ((newsv= (SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
+ savepoint_alloc_size)) == NULL)
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ newsv->name= strmake_root(&thd->transaction.mem_root, name.str, name.length);
+ newsv->length= name.length;
+
+ /*
+ if we'll get an error here, don't add new savepoint to the list.
+ we'll lose a little bit of memory in transaction mem_root, but it'll
+ be free'd when transaction ends anyway
+ */
+ if (ha_savepoint(thd, newsv))
+ DBUG_RETURN(TRUE);
+
+ newsv->prev= thd->transaction.savepoints;
+ thd->transaction.savepoints= newsv;
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ Rollback a transaction to the named savepoint.
+
+ @note Modifications that the current transaction made to
+ rows after the savepoint was set are undone in the
+ rollback.
+
+ @note Savepoints that were set at a later time than the
+ named savepoint are deleted.
+
+ @param thd Current thread
+ @param name Savepoint name
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
+{
+ int res= FALSE;
+ SAVEPOINT *sv= *find_savepoint(thd, name);
+ DBUG_ENTER("trans_rollback_to_savepoint");
+
+ if (sv == NULL)
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", name.str);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (ha_rollback_to_savepoint(thd, sv))
+ res= TRUE;
+ else if (((thd->options & OPTION_KEEP_LOG) ||
+ thd->transaction.all.modified_non_trans_table) &&
+ !thd->slave_thread)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARNING_NOT_COMPLETE_ROLLBACK,
+ ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
+
+ thd->transaction.savepoints= sv;
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Remove the named savepoint from the set of savepoints of
+ the current transaction.
+
+ @note No commit or rollback occurs. It is an error if the
+ savepoint does not exist.
+
+ @param thd Current thread
+ @param name Savepoint name
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_release_savepoint(THD *thd, LEX_STRING name)
+{
+ int res= FALSE;
+ SAVEPOINT *sv= *find_savepoint(thd, name);
+ DBUG_ENTER("trans_release_savepoint");
+
+ if (sv == NULL)
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", name.str);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (ha_release_savepoint(thd, sv))
+ res= TRUE;
+
+ thd->transaction.savepoints=sv->prev;
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
+ Starts an XA transaction with the given xid value.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_start(THD *thd)
+{
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ DBUG_ENTER("trans_xa_start");
+
+ if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
+ {
+ bool not_equal= !thd->transaction.xid_state.xid.eq(thd->lex->xid);
+ if (not_equal)
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ thd->transaction.xid_state.xa_state= XA_ACTIVE;
+ DBUG_RETURN(not_equal);
+ }
+
+ /* TODO: JOIN is not supported yet. */
+ if (thd->lex->xa_opt != XA_NONE)
+ my_error(ER_XAER_INVAL, MYF(0));
+ else if (xa_state != XA_NOTR)
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ else if (thd->locked_tables_mode || thd->active_transaction())
+ my_error(ER_XAER_OUTSIDE, MYF(0));
+ else if (xid_cache_search(thd->lex->xid))
+ my_error(ER_XAER_DUPID, MYF(0));
+ else if (!trans_begin(thd))
+ {
+ DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
+ thd->transaction.xid_state.xa_state= XA_ACTIVE;
+ thd->transaction.xid_state.xid.set(thd->lex->xid);
+ xid_cache_insert(&thd->transaction.xid_state);
+ DBUG_RETURN(FALSE);
+ }
+
+ DBUG_RETURN(TRUE);
+}
+
+
+/**
+ Put a XA transaction in the IDLE state.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_end(THD *thd)
+{
+ DBUG_ENTER("trans_xa_end");
+
+ /* TODO: SUSPEND and FOR MIGRATE are not supported yet. */
+ if (thd->lex->xa_opt != XA_NONE)
+ my_error(ER_XAER_INVAL, MYF(0));
+ else if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xid_state.xa_state]);
+ else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ thd->transaction.xid_state.xa_state= XA_IDLE;
+
+ DBUG_RETURN(thd->transaction.xid_state.xa_state != XA_IDLE);
+}
+
+
+/**
+ Put a XA transaction in the PREPARED state.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_prepare(THD *thd)
+{
+ DBUG_ENTER("trans_xa_prepare");
+
+ if (thd->transaction.xid_state.xa_state != XA_IDLE)
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xid_state.xa_state]);
+ else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+ my_error(ER_XAER_NOTA, MYF(0));
+ else if (ha_prepare(thd))
+ {
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state= XA_NOTR;
+ my_error(ER_XA_RBROLLBACK, MYF(0));
+ }
+ else
+ thd->transaction.xid_state.xa_state= XA_PREPARED;
+
+ DBUG_RETURN(thd->transaction.xid_state.xa_state != XA_PREPARED);
+}
+
+
+/**
+ Commit and terminate the a XA transaction.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_commit(THD *thd)
+{
+ bool res= TRUE;
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ DBUG_ENTER("trans_xa_commit");
+
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+ {
+ XID_STATE *xs= xid_cache_search(thd->lex->xid);
+ bool not_found= !xs || xs->in_thd;
+ if (not_found)
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ {
+ ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
+ xid_cache_delete(xs);
+ }
+ DBUG_RETURN(not_found);
+ }
+
+ if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
+ {
+ int r= ha_commit_trans(thd, TRUE);
+ if ((res= test(r)))
+ my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
+ }
+ else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
+ {
+ if (wait_if_global_read_lock(thd, 0, 0))
+ {
+ ha_rollback_trans(thd, TRUE);
+ my_error(ER_XAER_RMERR, MYF(0));
+ }
+ else
+ {
+ res= test(ha_commit_one_phase(thd, 1));
+ if (res)
+ my_error(ER_XAER_RMERR, MYF(0));
+ start_waiting_global_read_lock(thd);
+ }
+ }
+ else
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state= XA_NOTR;
+
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Roll back and terminate a XA transaction.
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_xa_rollback(THD *thd)
+{
+ bool res= TRUE;
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ DBUG_ENTER("trans_xa_rollback");
+
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
+ {
+ XID_STATE *xs= xid_cache_search(thd->lex->xid);
+ bool not_found= !xs || xs->in_thd;
+ if (not_found)
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ {
+ ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
+ xid_cache_delete(xs);
+ }
+ DBUG_RETURN(not_found);
+ }
+
+ if (xa_state != XA_IDLE && xa_state != XA_PREPARED)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_RETURN(TRUE);
+ }
+
+ if ((res= test(ha_rollback_trans(thd, TRUE))))
+ my_error(ER_XAER_RMERR, MYF(0));
+
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state= XA_NOTR;
+
+ DBUG_RETURN(res);
+}
=== added file 'sql/transaction.h'
--- a/sql/transaction.h 1970-01-01 00:00:00 +0000
+++ b/sql/transaction.h 2008-07-31 20:31:54 +0000
@@ -0,0 +1,46 @@
+/* Copyright (C) 2008 Sun/MySQL
+
+ 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+#ifndef TRANSACTION_H
+#define TRANSACTION_H
+
+class THD;
+
+/* Options of START TRANSACTION statement (and later of SET TRANSACTION stmt) */
+#define MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT (1U << 0)
+
+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_commit_stmt(THD *thd);
+bool trans_rollback_stmt(THD *thd);
+
+bool trans_savepoint(THD *thd, LEX_STRING name);
+bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name);
+bool trans_release_savepoint(THD *thd, LEX_STRING name);
+
+bool trans_xa_start(THD *thd);
+bool trans_xa_end(THD *thd);
+bool trans_xa_prepare(THD *thd);
+bool trans_xa_commit(THD *thd);
+bool trans_xa_rollback(THD *thd);
+
+#endif /* TRANSACTION_H */
=== modified file 'storage/maria/ha_maria.cc'
--- a/storage/maria/ha_maria.cc 2008-07-10 14:58:31 +0000
+++ b/storage/maria/ha_maria.cc 2008-07-31 20:31:54 +0000
@@ -2293,8 +2293,8 @@ int ha_maria::start_stmt(THD *thd, thr_l
This can be considered a hack. When Maria loses HA_NO_TRANSACTIONS it will
be participant in the connection's transaction and so the implicit commits
- (ha_commit()) (like in end_active_trans()) will do the implicit commit
- without need to call this function which can then be removed.
+ (ha_commit_trans()) (like in trans_commit_implicit()) will do the implicit
+ commit without need to call this function which can then be removed.
@param thd THD object
@param new_trn if a new transaction should be created; a new