#At file:///home/mikael/mysql_clones/LOCK_log/
2847 Mikael Ronstrom 2009-05-08
BUG#43362: Missing implicit commit after statements that commit
active transactions
This is backport to 5.1 of a patch from 6.0 that is part of the
work done for WL#4284 by Davi.
For statements that do an implicit commit before, there is a missing
commit after. This means that the statement can participate in the
following transaction, and it is especially important to get all
commits right for the binary logging to work correctly.
This patch adds two flags to the sql_command_flags: one for implicit
commit before and one for implicit commit after. It then extends the
command flags for the statements that do an implicit commit before to
use both these flags. The explicit calls to end_active_trans() for
statements doing implicit commit is removed and a new function
opt_implicit_commit() is added. This function will do an implicit
commit if the command flag says so, otherwise, it will do nothing.
In addition, the patch adds a new set of server command flags, which
are used to replace code that decide when next_query_id() should be
called and when statistics_increment() should be called. Instead,
there are now two new flags: one that can be set if the command should
skip increasing the statistics for questions, and one that can be set
if the command should not step the query id.
modified:
mysql-test/include/commit.inc
mysql-test/r/commit_1innodb.result
sql/events.cc
sql/mysql_priv.h
sql/sql_class.h
sql/sql_delete.cc
sql/sql_parse.cc
sql/sql_table.cc
tests/mysql_client_test.c
=== modified file 'mysql-test/include/commit.inc'
--- a/mysql-test/include/commit.inc 2009-01-23 12:22:05 +0000
+++ b/mysql-test/include/commit.inc 2009-05-08 13:25:22 +0000
@@ -729,15 +729,15 @@ call p_verify_status_increment(4, 4, 4,
alter table t3 add column (b int);
call p_verify_status_increment(2, 0, 2, 0);
alter table t3 rename t4;
-call p_verify_status_increment(1, 0, 1, 0);
+call p_verify_status_increment(2, 0, 2, 0);
rename table t4 to t3;
-call p_verify_status_increment(1, 0, 1, 0);
+call p_verify_status_increment(0, 0, 0, 0);
truncate table t3;
-call p_verify_status_increment(4, 4, 4, 4);
+call p_verify_status_increment(2, 2, 2, 2);
create view v1 as select * from t2;
-call p_verify_status_increment(1, 0, 1, 0);
+call p_verify_status_increment(2, 0, 2, 0);
check table t1;
-call p_verify_status_increment(3, 0, 3, 0);
+call p_verify_status_increment(2, 0, 2, 0);
--echo # Sic: after this bug is fixed, CHECK leaves no pending transaction
commit;
call p_verify_status_increment(0, 0, 0, 0);
=== modified file 'mysql-test/r/commit_1innodb.result'
--- a/mysql-test/r/commit_1innodb.result 2009-02-10 14:44:58 +0000
+++ b/mysql-test/r/commit_1innodb.result 2009-05-08 13:25:22 +0000
@@ -845,25 +845,25 @@ call p_verify_status_increment(2, 0, 2,
SUCCESS
alter table t3 rename t4;
-call p_verify_status_increment(1, 0, 1, 0);
+call p_verify_status_increment(2, 0, 2, 0);
SUCCESS
rename table t4 to t3;
-call p_verify_status_increment(1, 0, 1, 0);
+call p_verify_status_increment(0, 0, 0, 0);
SUCCESS
truncate table t3;
-call p_verify_status_increment(4, 4, 4, 4);
+call p_verify_status_increment(2, 2, 2, 2);
ERROR
-Expected commit increment: 4 actual: 2
+Expected prepare increment: 2 actual: 0
create view v1 as select * from t2;
-call p_verify_status_increment(1, 0, 1, 0);
+call p_verify_status_increment(2, 0, 2, 0);
SUCCESS
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
-call p_verify_status_increment(3, 0, 3, 0);
+call p_verify_status_increment(2, 0, 2, 0);
SUCCESS
# Sic: after this bug is fixed, CHECK leaves no pending transaction
=== modified file 'sql/events.cc'
--- a/sql/events.cc 2008-07-15 17:46:02 +0000
+++ b/sql/events.cc 2009-05-08 13:25:22 +0000
@@ -364,15 +364,6 @@ Events::create_event(THD *thd, Event_par
int ret;
DBUG_ENTER("Events::create_event");
- /*
- Let's commit the transaction first - MySQL manual specifies
- that a DDL issues an implicit commit, and it doesn't say "successful
- DDL", so that an implicit commit is a property of any successfully
- parsed DDL statement.
- */
- if (end_active_trans(thd))
- DBUG_RETURN(TRUE);
-
if (check_if_system_tables_error())
DBUG_RETURN(TRUE);
@@ -468,13 +459,6 @@ Events::update_event(THD *thd, Event_par
DBUG_ENTER("Events::update_event");
- /*
- For consistency, implicit COMMIT should be the first thing in the
- execution chain.
- */
- if (end_active_trans(thd))
- DBUG_RETURN(TRUE);
-
if (check_if_system_tables_error())
DBUG_RETURN(TRUE);
@@ -591,20 +575,6 @@ Events::drop_event(THD *thd, LEX_STRING
int ret;
DBUG_ENTER("Events::drop_event");
- /*
- In MySQL, DDL must always commit: since mysql.* tables are
- non-transactional, we must modify them outside a transaction
- to not break atomicity.
- But the second and more important reason to commit here
- regardless whether we're actually changing mysql.event table
- or not is replication: end_active_trans syncs the binary log,
- and unless we run DDL in it's own transaction it may simply
- never appear on the slave in case the outside transaction
- rolls back.
- */
- if (end_active_trans(thd))
- DBUG_RETURN(TRUE);
-
if (check_if_system_tables_error())
DBUG_RETURN(TRUE);
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2009-02-17 12:24:09 +0000
+++ b/sql/mysql_priv.h 2009-05-08 13:25:22 +0000
@@ -2036,8 +2036,8 @@ extern struct my_option my_long_options[
extern const LEX_STRING view_type;
extern scheduler_functions thread_scheduler;
extern TYPELIB thread_handling_typelib;
-extern uint8 uc_update_queries[SQLCOM_END+1];
extern uint sql_command_flags[];
+extern uint server_command_flags[];
extern TYPELIB log_output_typelib;
/* optional things, have_* variables */
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2009-02-17 12:24:09 +0000
+++ b/sql/sql_class.h 2009-05-08 13:25:22 +0000
@@ -2926,11 +2926,11 @@ public:
/* Bits in sql_command_flags */
-#define CF_CHANGES_DATA 1
-#define CF_HAS_ROW_COUNT 2
-#define CF_STATUS_COMMAND 4
-#define CF_SHOW_TABLE_COMMAND 8
-#define CF_WRITE_LOGS_COMMAND 16
+#define CF_CHANGES_DATA (1U << 0)
+#define CF_HAS_ROW_COUNT (1U << 1)
+#define CF_STATUS_COMMAND (1U << 2)
+#define CF_SHOW_TABLE_COMMAND (1U << 3)
+#define CF_WRITE_LOGS_COMMAND (1U << 4)
/**
Must be set for SQL statements that may contain
Item expressions and/or use joins and tables.
@@ -2944,7 +2944,54 @@ public:
reprepare. Consequently, complex item expressions and
joins are currently prohibited in these statements.
*/
-#define CF_REEXECUTION_FRAGILE 32
+#define CF_REEXECUTION_FRAGILE (1U << 5)
+/**
+ Implicitly commit before the SQL statement is executed.
+
+ Statements marked with this flag will cause any active
+ transaction to end (commit) before proceeding with the
+ command execution.
+
+ This flag should be set for statements that probably can't
+ be rolled back or that do not expect any previously metadata
+ locked tables.
+*/
+#define CF_IMPLICT_COMMIT_BEGIN (1U << 6)
+/**
+ Implicitly commit after the SQL statement.
+
+ Statements marked with this flag are automatically committed
+ at the end of the statement.
+
+ This flag should be set for statements that will implicitly
+ open and take metadata locks on system tables that should not
+ be carried for the whole duration of a active transaction.
+*/
+#define CF_IMPLICIT_COMMIT_END (1U << 7)
+/**
+ CF_IMPLICT_COMMIT_BEGIN and CF_IMPLICIT_COMMIT_END are used
+ to ensure that the active transaction is implicitly committed
+ before and after every DDL statement and any statement that
+ modifies our currently non-transactional system tables.
+*/
+#define CF_AUTO_COMMIT_TRANS (CF_IMPLICT_COMMIT_BEGIN | CF_IMPLICIT_COMMIT_END)
+
+/* Bits in server_command_flags */
+
+/**
+ Skip the increase of the global query id counter. Commonly set for
+ commands that are stateless (won't cause any change on the server
+ internal states).
+*/
+#define CF_SKIP_QUERY_ID (1U << 0)
+
+/**
+ Skip the increase of the number of statements that clients have
+ sent to the server. Commonly used for commands that will cause
+ a statement to be executed but the statement might have not been
+ sent by the user (ie: stored procedure).
+*/
+#define CF_SKIP_QUESTIONS (1U << 1)
/* Functions in sql_class.cc */
=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc 2009-02-09 22:51:59 +0000
+++ b/sql/sql_delete.cc 2009-05-08 13:25:22 +0000
@@ -981,8 +981,6 @@ static bool mysql_truncate_by_delete(THD
mysql_init_select(thd->lex);
thd->clear_current_stmt_binlog_row_based();
error= mysql_delete(thd, table_list, NULL, NULL, HA_POS_ERROR, LL(0), TRUE);
- ha_autocommit_or_rollback(thd, error);
- end_trans(thd, error ? ROLLBACK : COMMIT);
thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(error);
}
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2009-02-17 12:24:09 +0000
+++ b/sql/sql_parse.cc 2009-05-08 13:25:22 +0000
@@ -230,6 +230,50 @@ static bool some_non_temp_table_to_be_up
}
+/*
+ Implicitly commit a active transaction if statement requires so.
+
+ @param thd Thread handle.
+ @param mask Bitmask used for the SQL command match.
+
+*/
+static bool opt_implicit_commit(THD *thd, uint mask)
+{
+ LEX *lex= thd->lex;
+ bool res= FALSE, skip= FALSE;
+ DBUG_ENTER("opt_implicit_commit");
+
+ if (!(sql_command_flags[lex->sql_command] & mask))
+ DBUG_RETURN(FALSE);
+
+ switch (lex->sql_command) {
+ case SQLCOM_DROP_TABLE:
+ skip= lex->drop_temporary;
+ break;
+ case SQLCOM_ALTER_TABLE:
+ case SQLCOM_CREATE_TABLE:
+ /* If CREATE TABLE of non-temporary table, do implicit commit */
+ skip= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE);
+ break;
+ case SQLCOM_SET_OPTION:
+ skip= lex->autocommit ? FALSE : TRUE;
+ break;
+ default:
+ break;
+ }
+
+ if (!skip)
+ {
+ /* Commit or rollback the statement transaction. */
+ ha_autocommit_or_rollback(thd, thd->is_error());
+ /* Commit the normal transaction if one is active. */
+ res= end_active_trans(thd);
+ }
+
+ DBUG_RETURN(res);
+}
+
+
/**
Mark all commands that somehow changes a table.
@@ -244,28 +288,46 @@ static bool some_non_temp_table_to_be_up
*/
uint sql_command_flags[SQLCOM_END+1];
+uint server_command_flags[COM_END+1];
void init_update_queries(void)
{
- bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
+ /* Initialize the server command flags array. */
+ memset(server_command_flags, 0, sizeof(server_command_flags));
- sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
- sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
- sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA;
+ server_command_flags[COM_STATISTICS]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS;
+ server_command_flags[COM_PING]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS;
+ server_command_flags[COM_STMT_PREPARE]= CF_SKIP_QUESTIONS;
+ server_command_flags[COM_STMT_CLOSE]= CF_SKIP_QUESTIONS;
+ server_command_flags[COM_STMT_RESET]= CF_SKIP_QUESTIONS;
+
+ /* Initialize the sql command flags array. */
+ memset(sql_command_flags, 0, sizeof(sql_command_flags));
+
+ sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_BACKUP_TABLE]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_RESTORE_TABLE]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA;
- sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
CF_REEXECUTION_FRAGILE;
@@ -284,7 +346,8 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE;
+ sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE |
+ CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
@@ -349,9 +412,29 @@ void init_update_queries(void)
The following admin table operations are allowed
on log tables.
*/
- sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND;
- sql_command_flags[SQLCOM_OPTIMIZE]= CF_WRITE_LOGS_COMMAND;
- sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND;
+ sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_OPTIMIZE]= CF_WRITE_LOGS_COMMAND |
+ CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND |
+ CF_AUTO_COMMIT_TRANS;
+
+ sql_command_flags[SQLCOM_CREATE_USER]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_USER]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_RENAME_USER]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_REVOKE_ALL]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_REVOKE]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_GRANT]= CF_AUTO_COMMIT_TRANS;
+
+ sql_command_flags[SQLCOM_CREATE_PROCEDURE]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_SPFUNCTION]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_PROCEDURE]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ALTER_FUNCTION]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_PRELOAD_KEYS]= CF_AUTO_COMMIT_TRANS;
+
+ sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS;
}
@@ -976,27 +1059,13 @@ bool dispatch_command(enum enum_server_c
thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id= global_query_id;
-
- switch( command ) {
- /* Ignore these statements. */
- case COM_STATISTICS:
- case COM_PING:
- break;
- /* Only increase id on these statements but don't count them. */
- case COM_STMT_PREPARE:
- case COM_STMT_CLOSE:
- case COM_STMT_RESET:
- next_query_id();
- break;
- /* Increase id and count all other statements. */
- default:
- statistic_increment(thd->status_var.questions, &LOCK_status);
+ if (!(server_command_flags[command] & CF_SKIP_QUERY_ID))
next_query_id();
- }
-
thread_running++;
- /* TODO: set thd->lex->sql_command to SQLCOM_END here */
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ if (!(server_command_flags[command] & CF_SKIP_QUESTIONS))
+ statistic_increment(thd->status_var.questions, &LOCK_status);
/**
Clear the set of flags that are expected to be cleared at the
@@ -1436,11 +1505,16 @@ 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))
+ 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))
- my_ok(thd);
+ if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used))
+ break;
+ if (end_active_trans(thd))
+ break;
+ my_ok(thd);
break;
}
#ifndef EMBEDDED_LIBRARY
@@ -1654,8 +1728,8 @@ void log_slow_statement(THD *thd)
*/
if (thd->enable_slow_log && !thd->user_time)
{
- ulonglong end_utime_of_query= thd->current_utime();
thd_proc_info(thd, "logging slow query");
+ ulonglong end_utime_of_query= thd->current_utime();
if (((end_utime_of_query - thd->utime_after_lock) >
thd->variables.long_query_time ||
@@ -2172,6 +2246,15 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
+ /*
+ End a active transaction so that this command will have it's
+ own transaction and will also sync the binary log. If a DDL is
+ not run in it's own transaction it may simply never appear on
+ the slave in case the outside transaction rolls back.
+ */
+ if (opt_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN))
+ goto error;
+
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
@@ -2218,21 +2301,27 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_PROFILE:
case SQLCOM_SELECT:
+ {
thd->status_var.last_query_cost= 0.0;
+
+ /*
+ lex->exchange != NULL implies SELECT .. INTO OUTFILE and this
+ requires FILE_ACL access.
+ */
+ ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
+ SELECT_ACL;
if (all_tables)
- {
res= check_table_access(thd,
- lex->exchange ? SELECT_ACL | FILE_ACL :
- SELECT_ACL,
+ privileges_requested,
all_tables, UINT_MAX, FALSE);
- }
else
res= check_access(thd,
- lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
+ privileges_requested,
any_db, 0, 0, 0, 0);
if (!res)
res= execute_sqlcom_select(thd, all_tables);
break;
+ }
case SQLCOM_PREPARE:
{
mysql_sql_stmt_prepare(thd);
@@ -2491,15 +2580,6 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_TABLE:
{
- /* If CREATE TABLE of non-temporary table, do implicit commit */
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
- {
- if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
- }
DBUG_ASSERT(first_table == all_tables && first_table != 0);
bool link_to_local;
// Skip first table, which is the table we are creating
@@ -2715,8 +2795,6 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- goto error;
/*
Currently CREATE INDEX or DROP INDEX cause a full table rebuild
and thus classify as slow administrative statements just like
@@ -2828,9 +2906,6 @@ end_with_restore_list:
WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
"INDEX DIRECTORY");
create_info.data_file_name= create_info.index_file_name= NULL;
- /* ALTER TABLE ends previous transaction */
- if (end_active_trans(thd))
- goto error;
if (!thd->locked_tables &&
!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
@@ -2875,7 +2950,7 @@ end_with_restore_list:
goto error;
}
- if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
+ if (mysql_rename_tables(thd, first_table, 0))
goto error;
break;
}
@@ -3228,11 +3303,6 @@ end_with_restore_list:
break;
}
case SQLCOM_TRUNCATE:
- if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, DROP_ACL, all_tables))
goto error;
@@ -3339,8 +3409,6 @@ end_with_restore_list:
{
if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- goto error;
}
else
{
@@ -3438,9 +3506,6 @@ end_with_restore_list:
{
List<set_var_base> *lex_var_list= &lex->var_list;
- if (lex->autocommit && end_active_trans(thd))
- goto error;
-
if ((check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
open_and_lock_tables(thd, all_tables)))
goto error;
@@ -3532,11 +3597,6 @@ end_with_restore_list:
prepared statement- safe.
*/
HA_CREATE_INFO create_info(lex->create_info);
- if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
char *alias;
if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
check_db_name(&lex->name))
@@ -3569,11 +3629,6 @@ end_with_restore_list:
}
case SQLCOM_DROP_DB:
{
- if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
if (check_db_name(&lex->name))
{
my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
@@ -3610,11 +3665,6 @@ end_with_restore_list:
case SQLCOM_ALTER_DB_UPGRADE:
{
LEX_STRING *db= & lex->name;
- if (end_active_trans(thd))
- {
- res= 1;
- break;
- }
#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
(!rpl_filter->db_ok(db->str) ||
@@ -3777,8 +3827,6 @@ end_with_restore_list:
if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- if (end_active_trans(thd))
- goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_create_user(thd, lex->users_list)))
my_ok(thd);
@@ -3789,8 +3837,6 @@ end_with_restore_list:
if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- if (end_active_trans(thd))
- goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_drop_user(thd, lex->users_list)))
my_ok(thd);
@@ -3801,8 +3847,6 @@ end_with_restore_list:
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- if (end_active_trans(thd))
- goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_rename_user(thd, lex->users_list)))
my_ok(thd);
@@ -3810,8 +3854,6 @@ end_with_restore_list:
}
case SQLCOM_REVOKE_ALL:
{
- if (end_active_trans(thd))
- goto error;
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
@@ -3823,9 +3865,6 @@ end_with_restore_list:
case SQLCOM_REVOKE:
case SQLCOM_GRANT:
{
- if (end_active_trans(thd))
- goto error;
-
if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
first_table ? first_table->db : select_lex->db,
first_table ? &first_table->grant.privilege : 0,
@@ -4170,9 +4209,6 @@ end_with_restore_list:
is_schema_db(lex->sphead->m_db.str)))
goto create_sp_error;
- if (end_active_trans(thd))
- goto create_sp_error;
-
name= lex->sphead->name(&namelen);
#ifdef HAVE_DLOPEN
if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
@@ -4367,8 +4403,6 @@ create_sp_error:
lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
goto error;
- if (end_active_trans(thd))
- goto error;
memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
!trust_function_creators && mysql_bin_log.is_open() &&
@@ -4568,16 +4602,12 @@ create_sp_error:
Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
as specified through the thd->lex->create_view_mode flag.
*/
- if (end_active_trans(thd))
- goto error;
-
res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
break;
}
case SQLCOM_DROP_VIEW:
{
- if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE) ||
- end_active_trans(thd))
+ if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE))
goto error;
/* Conditionally writes to binlog. */
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
@@ -4585,9 +4615,6 @@ create_sp_error:
}
case SQLCOM_CREATE_TRIGGER:
{
- if (end_active_trans(thd))
- goto error;
-
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 1);
@@ -4595,9 +4622,6 @@ create_sp_error:
}
case SQLCOM_DROP_TRIGGER:
{
- if (end_active_trans(thd))
- goto error;
-
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break;
@@ -4919,6 +4943,12 @@ finish:
*/
start_waiting_global_read_lock(thd);
}
+
+ /* If commit fails, we should be able to reset the OK status. */
+ thd->main_da.can_overwrite_status= TRUE;
+ opt_implicit_commit(thd, CF_IMPLICIT_COMMIT_END);
+ thd->main_da.can_overwrite_status= FALSE;
+
DBUG_RETURN(res || thd->is_error());
}
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2009-02-05 06:16:00 +0000
+++ b/sql/sql_table.cc 2009-05-08 13:25:22 +0000
@@ -4159,8 +4159,6 @@ static bool mysql_admin_table(THD* thd,
int result_code;
DBUG_ENTER("mysql_admin_table");
- if (end_active_trans(thd))
- DBUG_RETURN(1);
field_list.push_back(item = new Item_empty_string("Table", NAME_CHAR_LEN*2));
item->maybe_null = 1;
field_list.push_back(item = new Item_empty_string("Op", 10));
=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c 2009-01-15 10:28:10 +0000
+++ b/tests/mysql_client_test.c 2009-05-08 13:25:22 +0000
@@ -17769,6 +17769,59 @@ static void test_bug36326()
#endif
+/**
+ Test that COM_REFRESH issues a implicit commit.
+*/
+
+static void test_wl4284_1()
+{
+ int rc;
+ MYSQL_ROW row;
+ MYSQL_RES *result;
+
+ DBUG_ENTER("test_wl4284_1");
+ myheader("test_wl4284_1");
+
+ /* set AUTOCOMMIT to OFF */
+ rc= mysql_autocommit(mysql, FALSE);
+ myquery(rc);
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS trans");
+ myquery(rc);
+
+ rc= mysql_query(mysql, "CREATE TABLE trans (a INT) ENGINE= InnoDB");
+ myquery(rc);
+
+ rc= mysql_query(mysql, "INSERT INTO trans VALUES(1)");
+ myquery(rc);
+
+ rc= mysql_refresh(mysql, REFRESH_GRANT | REFRESH_TABLES);
+ myquery(rc);
+
+ rc= mysql_rollback(mysql);
+ myquery(rc);
+
+ rc= mysql_query(mysql, "SELECT * FROM trans");
+ myquery(rc);
+
+ result= mysql_use_result(mysql);
+ mytest(result);
+
+ row= mysql_fetch_row(result);
+ mytest(row);
+
+ mysql_free_result(result);
+
+ /* set AUTOCOMMIT to OFF */
+ rc= mysql_autocommit(mysql, FALSE);
+ myquery(rc);
+
+ rc= mysql_query(mysql, "DROP TABLE trans");
+ myquery(rc);
+
+ DBUG_VOID_RETURN;
+}
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -18085,6 +18138,7 @@ static struct my_tests_st my_tests[]= {
#ifdef HAVE_QUERY_CACHE
{ "test_bug36326", test_bug36326 },
#endif
+ { "test_wl4284_1", test_wl4284_1 },
{ 0, 0 }
};
| Thread |
|---|
| • bzr commit into mysql-5.1 branch (mikael:2847) Bug#43362 | Mikael Ronstrom | 11 May |