summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlfranio Correia <alfranio.correia@sun.com>2010-03-31 14:30:24 +0100
committerAlfranio Correia <alfranio.correia@sun.com>2010-03-31 14:30:24 +0100
commit671f8768bbf437c4ef546a73ccec2d472485528a (patch)
tree76af6a16f7a21178e722d6b90b26529ef26255b4 /sql
parentbd92aec362ebd5c65f3c3b8e99a7e35a5bafede1 (diff)
parent41c642e634f8d7b8d6aef4b4c94783c96c2be711 (diff)
downloadmariadb-git-671f8768bbf437c4ef546a73ccec2d472485528a.tar.gz
auto-merge mysql-trunk-bugfixing (local) --> mysql-trunk-bugfixing
Diffstat (limited to 'sql')
-rw-r--r--sql/log.cc30
-rw-r--r--sql/share/errmsg-utf8.txt6
-rw-r--r--sql/sql_class.cc98
-rw-r--r--sql/sql_lex.cc4
-rw-r--r--sql/sql_lex.h12
5 files changed, 105 insertions, 45 deletions
diff --git a/sql/log.cc b/sql/log.cc
index 279782d271b..a83eca12481 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1631,7 +1631,10 @@ binlog_flush_stmt_cache(THD *thd, binlog_cache_mngr *cache_mngr)
*/
bool const is_transactional= FALSE;
IO_CACHE *cache_log= &cache_mngr->stmt_cache.cache_log;
- thd->binlog_flush_pending_rows_event(TRUE, is_transactional);
+
+ if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
+ DBUG_RETURN(1);
+
Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
if ((error= mysql_bin_log.write(thd, cache_log, &qev,
cache_mngr->stmt_cache.has_incident())))
@@ -4180,7 +4183,7 @@ bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
}
/**
- This function checks if a transactional talbe was updated by the
+ This function checks if a transactional table was updated by the
current transaction.
@param thd The client thread that executed the current statement.
@@ -4193,11 +4196,11 @@ trans_has_updated_trans_table(const THD* thd)
binlog_cache_mngr *const cache_mngr=
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
- return (cache_mngr ? my_b_tell (&cache_mngr->trx_cache.cache_log) : 0);
+ return (cache_mngr ? !cache_mngr->trx_cache.empty() : 0);
}
/**
- This function checks if a transactional talbe was updated by the
+ This function checks if a transactional table was updated by the
current statement.
@param thd The client thread that executed the current statement.
@@ -4209,7 +4212,8 @@ stmt_has_updated_trans_table(const THD *thd)
{
Ha_trx_info *ha_info;
- for (ha_info= thd->transaction.stmt.ha_list; ha_info; ha_info= ha_info->next())
+ for (ha_info= thd->transaction.stmt.ha_list; ha_info;
+ ha_info= ha_info->next())
{
if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
return (TRUE);
@@ -4219,11 +4223,14 @@ stmt_has_updated_trans_table(const THD *thd)
/**
This function checks if either a trx-cache or a non-trx-cache should
- be used. If @c bin_log_direct_non_trans_update is active, the cache
- to be used depends on the flag @c is_transactional.
+ be used. If @c bin_log_direct_non_trans_update is active or the format
+ is either MIXED or ROW, the cache to be used depends on the flag @c
+ is_transactional.
- Otherswise, we use the trx-cache if either the @c is_transactional
- is true or the trx-cache is not empty.
+ On the other hand, if binlog_format is STMT or direct option is
+ OFF, the trx-cache should be used if and only if the statement is
+ transactional or the trx-cache is not empty. Otherwise, the
+ non-trx-cache should be used.
@param thd The client thread.
@param is_transactional The changes are related to a trx-table.
@@ -4236,8 +4243,9 @@ bool use_trans_cache(const THD* thd, bool is_transactional)
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
return
- (thd->variables.binlog_direct_non_trans_update ? is_transactional :
- (cache_mngr->trx_cache.empty() && !is_transactional ? FALSE : TRUE));
+ ((thd->variables.binlog_format != BINLOG_FORMAT_STMT ||
+ thd->variables.binlog_direct_non_trans_update) ? is_transactional :
+ (is_transactional || cache_mngr->trx_cache.empty()));
}
/*
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 517782cb0b4..2b778abc97b 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6327,3 +6327,9 @@ ER_LOCK_ABORTED
ER_DATA_OUT_OF_RANGE 22003
eng "%s value is out of range in '%s'"
+
+ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE
+ eng "Mixing self-logging and non-self-logging engines in a statement is unsafe."
+
+ER_BINLOG_UNSAFE_MIXED_STATEMENT
+ eng "Statements that read from both transactional and non-transactional tables and write to any of them are unsafe."
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 4b21bc283e2..ffceb2eabce 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -3589,13 +3589,33 @@ int THD::decide_logging_format(TABLE_LIST *tables)
capabilities, and one with the intersection of all the engine
capabilities.
*/
+ handler::Table_flags flags_write_some_set= 0;
handler::Table_flags flags_some_set= 0;
- handler::Table_flags flags_all_set=
+ handler::Table_flags flags_write_all_set=
HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
- my_bool multi_engine= FALSE;
- my_bool mixed_engine= FALSE;
- my_bool all_trans_engines= TRUE;
+ /*
+ If different types of engines are about to be updated.
+ For example: Innodb and Falcon; Innodb and MyIsam.
+ */
+ my_bool multi_write_engine= FALSE;
+ /*
+ If different types of engines are about to be accessed
+ and any of them is about to be updated. For example:
+ Innodb and Falcon; Innodb and MyIsam.
+ */
+ my_bool multi_access_engine= FALSE;
+ /*
+ If non-transactional and transactional engines are about
+ to be accessed and any of them is about to be updated.
+ For example: Innodb and MyIsam.
+ */
+ my_bool trans_non_trans_access_engines= FALSE;
+ /*
+ If all engines that are about to be updated are
+ transactional.
+ */
+ my_bool all_trans_write_engines= TRUE;
TABLE* prev_write_table= NULL;
TABLE* prev_access_table= NULL;
@@ -3621,32 +3641,50 @@ int THD::decide_logging_format(TABLE_LIST *tables)
continue;
if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE)
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
+ handler::Table_flags const flags= table->table->file->ha_table_flags();
+ DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
+ table->table_name, flags));
if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
{
- handler::Table_flags const flags= table->table->file->ha_table_flags();
- DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
- table->table_name, flags));
if (prev_write_table && prev_write_table->file->ht !=
table->table->file->ht)
- multi_engine= TRUE;
- all_trans_engines= all_trans_engines &&
- table->table->file->has_transactions();
+ multi_write_engine= TRUE;
+ all_trans_write_engines= all_trans_write_engines &&
+ table->table->file->has_transactions();
prev_write_table= table->table;
- flags_all_set &= flags;
- flags_some_set |= flags;
+ flags_write_all_set &= flags;
+ flags_write_some_set |= flags;
}
+ flags_some_set |= flags;
if (prev_access_table && prev_access_table->file->ht != table->table->file->ht)
- mixed_engine= mixed_engine || (prev_access_table->file->has_transactions() !=
- table->table->file->has_transactions());
+ {
+ multi_access_engine= TRUE;
+ trans_non_trans_access_engines= trans_non_trans_access_engines ||
+ (prev_access_table->file->has_transactions() !=
+ table->table->file->has_transactions());
+ }
prev_access_table= table->table;
}
+ DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
+ DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
+ DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set));
+ DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
+ DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
+ DBUG_PRINT("info", ("trans_non_trans_access_engines: %d",
+ trans_non_trans_access_engines));
+
+ int error= 0;
+ int unsafe_flags;
+
/*
Set the statement as unsafe if:
. it is a mixed statement, i.e. access transactional and non-transactional
- tables, and updates at least one;
- or
+ tables, and update any of them;
+
+ or:
+
. an early statement updated a transactional table;
. and, the current statement updates a non-transactional table.
@@ -3710,32 +3748,26 @@ int THD::decide_logging_format(TABLE_LIST *tables)
isolation level but if we have pure repeatable read or serializable the
lock history on the slave will be different from the master.
*/
- if (mixed_engine ||
- (trans_has_updated_trans_table(this) && !all_trans_engines))
+ if (!trans_non_trans_access_engines)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
+ else if (trans_has_updated_trans_table(this) && !all_trans_write_engines)
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
- DBUG_PRINT("info", ("flags_all_set: 0x%llx", flags_all_set));
- DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set));
- DBUG_PRINT("info", ("multi_engine: %d", multi_engine));
-
- int error= 0;
- int unsafe_flags;
-
/*
If more than one engine is involved in the statement and at
least one is doing it's own logging (is *self-logging*), the
statement cannot be logged atomically, so we generate an error
rather than allowing the binlog to become corrupt.
*/
- if (multi_engine &&
- (flags_some_set & HA_HAS_OWN_BINLOGGING))
- {
+ if (multi_write_engine &&
+ (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
MYF(0));
- }
+ else if (multi_access_engine && flags_some_set & HA_HAS_OWN_BINLOGGING)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
/* both statement-only and row-only engines involved */
- if ((flags_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) == 0)
+ if ((flags_write_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) == 0)
{
/*
1. Error: Binary logging impossible since both row-incapable
@@ -3744,7 +3776,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
my_error((error= ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
}
/* statement-only engines involved */
- else if ((flags_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
+ else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
{
if (lex->is_stmt_row_injection())
{
@@ -3792,7 +3824,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
*/
my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
}
- else if ((flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
+ else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
{
/*
5. Error: Cannot modify table that uses a storage engine
@@ -3820,7 +3852,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
else
{
if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection()
- || (flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
+ || (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
{
/* log in row format! */
set_current_stmt_binlog_format_row_if_mixed();
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 14b5e160629..0f49abe9abd 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -52,7 +52,9 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
ER_BINLOG_UNSAFE_UDF,
ER_BINLOG_UNSAFE_SYSTEM_VARIABLE,
ER_BINLOG_UNSAFE_SYSTEM_FUNCTION,
- ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS
+ ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS,
+ ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE,
+ ER_BINLOG_UNSAFE_MIXED_STATEMENT,
};
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 0b27f73e763..7b655889a5f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1143,6 +1143,18 @@ public:
*/
BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS,
+ /**
+ Mixing self-logging and non-self-logging engines in a statement
+ is unsafe.
+ */
+ BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE,
+
+ /**
+ Statements that read from both transactional and non-transactional
+ tables and write to any of them are unsafe.
+ */
+ BINLOG_STMT_UNSAFE_MIXED_STATEMENT,
+
/* The last element of this enumeration type. */
BINLOG_STMT_UNSAFE_COUNT
};