summaryrefslogtreecommitdiff
path: root/sql/sql_class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r--sql/sql_class.cc326
1 files changed, 162 insertions, 164 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b1e416257ec..eb4d353db81 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -100,8 +100,8 @@ extern "C" void free_user_var(user_var_entry *entry)
{
char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
if (entry->value && entry->value != pos)
- my_free(entry->value, MYF(0));
- my_free((char*) entry,MYF(0));
+ my_free(entry->value);
+ my_free(entry);
}
bool Key_part_spec::operator==(const Key_part_spec& other) const
@@ -493,7 +493,9 @@ THD::THD()
rli_fake(0),
lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0),
- binlog_unsafe_warning_flags(0), binlog_table_maps(0),
+ binlog_unsafe_warning_flags(0),
+ stmt_accessed_table_flag(0),
+ binlog_table_maps(0),
table_map_for_update(0),
arg_of_last_insert_id_function(FALSE),
first_successful_insert_id_in_prev_stmt(0),
@@ -537,7 +539,7 @@ THD::THD()
count_cuted_fields= CHECK_FIELD_IGNORE;
killed= NOT_KILLED;
col_access=0;
- is_slave_error= thread_specific_used= thread_temporary_used= FALSE;
+ is_slave_error= thread_specific_used= FALSE;
my_hash_clear(&handler_tables_hash);
tmp_table=0;
used_tables=0;
@@ -1123,7 +1125,8 @@ THD::~THD()
DBUG_PRINT("info", ("freeing security context"));
main_security_ctx.destroy();
- safeFree(db);
+ my_free(db);
+ db= NULL;
free_root(&transaction.mem_root,MYF(0));
mysys_var=0; // Safety (shouldn't be needed)
mysql_mutex_destroy(&LOCK_thd_data);
@@ -2962,10 +2965,18 @@ void Security_context::destroy()
{
// If not pointer to constant
if (host != my_localhost)
- safeFree(host);
+ {
+ my_free(host);
+ host= NULL;
+ }
if (user != delayed_user)
- safeFree(user);
- safeFree(ip);
+ {
+ my_free(user);
+ user= NULL;
+ }
+
+ my_free(ip);
+ ip= NULL;
}
@@ -2981,7 +2992,7 @@ void Security_context::skip_grants()
bool Security_context::set_user(char *user_arg)
{
- safeFree(user);
+ my_free(user);
user= my_strdup(user_arg, MYF(0));
return user == 0;
}
@@ -3473,7 +3484,7 @@ uchar *xid_get_hash_key(const uchar *ptr, size_t *length,
void xid_free_hash(void *ptr)
{
if (!((XID_STATE*)ptr)->in_thd)
- my_free((uchar*)ptr, MYF(0));
+ my_free(ptr);
}
#ifdef HAVE_PSI_INTERFACE
@@ -3689,7 +3700,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
capabilities.
*/
handler::Table_flags flags_write_some_set= 0;
- handler::Table_flags flags_some_set= 0;
+ handler::Table_flags flags_access_some_set= 0;
handler::Table_flags flags_write_all_set=
HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
@@ -3704,17 +3715,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
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;
@@ -3738,9 +3739,12 @@ int THD::decide_logging_format(TABLE_LIST *tables)
{
if (table->placeholder())
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)
@@ -3748,177 +3752,171 @@ int THD::decide_logging_format(TABLE_LIST *tables)
if (prev_write_table && prev_write_table->file->ht !=
table->table->file->ht)
multi_write_engine= TRUE;
- /*
- Every temporary table must be always written to the binary
- log in transaction boundaries and as such we artificially
- classify them as transactional.
- Indirectly, this avoids classifying a temporary table created
- on a non-transactional engine as unsafe when it is modified
- after any transactional table:
+ my_bool trans= table->table->file->has_transactions();
- BEGIN;
- INSERT INTO innodb_t VALUES (1);
- INSERT INTO myisam_t_temp VALUES (1);
- COMMIT;
-
- BINARY LOG:
+ if (table->table->s->tmp_table)
+ set_stmt_accessed_table(trans ? STMT_WRITES_TEMP_TRANS_TABLE :
+ STMT_WRITES_TEMP_NON_TRANS_TABLE);
+ else
+ set_stmt_accessed_table(trans ? STMT_WRITES_TRANS_TABLE :
+ STMT_WRITES_NON_TRANS_TABLE);
- BEGIN;
- INSERT INTO innodb_t VALUES (1);
- INSERT INTO myisam_t_temp VALUES (1);
- COMMIT;
- */
- all_trans_write_engines= all_trans_write_engines &&
- (table->table->file->has_transactions() ||
- table->table->s->tmp_table);
- prev_write_table= table->table;
flags_write_all_set &= flags;
flags_write_some_set |= flags;
- }
- flags_some_set |= flags;
- /*
- The mixture of non-transactional and transactional tables must
- identified and classified as unsafe. However, a temporary table
- must be always handled as a transactional table. Based on that,
- we have the following statements classified as mixed and by
- consequence as unsafe:
-
- 1: INSERT INTO myisam_t SELECT * FROM innodb_t;
-
- 2: INSERT INTO innodb_t SELECT * FROM myisam_t;
-
- 3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
-
- 4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
- 5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
-
- The following statements are not considered mixed and as such
- are safe:
-
- 1: INSERT INTO innodb_t SELECT * FROM myisam_t_temp;
+ prev_write_table= table->table;
+ }
+ flags_access_some_set |= flags;
- 2: INSERT INTO myisam_t_temp SELECT * FROM innodb_t_temp;
- */
- if (!trans_non_trans_access_engines && prev_access_table &&
- (lex->sql_command != SQLCOM_CREATE_TABLE ||
+ if (lex->sql_command != SQLCOM_CREATE_TABLE ||
(lex->sql_command == SQLCOM_CREATE_TABLE &&
- (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))))
+ (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)))
{
- my_bool prev_trans;
- my_bool act_trans;
- if (prev_access_table->s->tmp_table || table->table->s->tmp_table)
- {
- prev_trans= prev_access_table->s->tmp_table ? TRUE :
- prev_access_table->file->has_transactions();
- act_trans= table->table->s->tmp_table ? TRUE :
- table->table->file->has_transactions();
- }
+ my_bool trans= table->table->file->has_transactions();
+
+ if (table->table->s->tmp_table)
+ set_stmt_accessed_table(trans ? STMT_READS_TEMP_TRANS_TABLE :
+ STMT_READS_TEMP_NON_TRANS_TABLE);
else
- {
- prev_trans= prev_access_table->file->has_transactions();
- act_trans= table->table->file->has_transactions();
- }
- trans_non_trans_access_engines= (prev_trans != act_trans);
- multi_access_engine= TRUE;
+ set_stmt_accessed_table(trans ? STMT_READS_TRANS_TABLE :
+ STMT_READS_NON_TRANS_TABLE);
}
- thread_temporary_used |= table->table->s->tmp_table;
+
+ if (prev_access_table && prev_access_table->file->ht !=
+ table->table->file->ht)
+ multi_access_engine= TRUE;
+
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", ("flags_access_some_set: 0x%llx", flags_access_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 update any of them;
-
- or:
-
- . an early statement updated a transactional table;
- . and, the current statement updates a non-transactional table.
-
- Any mixed statement is classified as unsafe to ensure that mixed mode is
- completely safe. Consider the following example to understand why we
- decided to do this:
-
- Note that mixed statements such as
-
- 1: INSERT INTO myisam_t SELECT * FROM innodb_t;
-
- 2: INSERT INTO innodb_t SELECT * FROM myisam_t;
-
- 3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
-
- 4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
-
- 5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
+ Classify a statement as unsafe when there is a mixed statement and an
+ on-going transaction at any point of the execution if:
- are classified as unsafe to ensure that in mixed mode the execution is
- completely safe and equivalent to the row mode. Consider the following
- statements and sessions (connections) to understand the reason:
+ 1. The mixed statement is about to update a transactional table and
+ a non-transactional table.
- con1: INSERT INTO innodb_t VALUES (1);
- con1: INSERT INTO innodb_t VALUES (100);
+ 2. The mixed statement is about to update a temporary transactional
+ table and a non-transactional table.
+
+ 3. The mixed statement is about to update a transactional table and
+ read from a non-transactional table.
- con1: BEGIN
- con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
- con1: INSERT INTO innodb_t VALUES (200);
- con1: COMMIT;
+ 4. The mixed statement is about to update a temporary transactional
+ table and read from a non-transactional table.
- The point is that the concurrent statements may be written into the binary log
- in a way different from the execution. For example,
+ 5. The mixed statement is about to update a non-transactional table
+ and read from a transactional table when the isolation level is
+ lower than repeatable read.
- BINARY LOG:
+ After updating a transactional table if:
- con2: BEGIN;
- con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
- con2: COMMIT;
- con1: BEGIN
- con1: INSERT INTO innodb_t VALUES (200);
- con1: COMMIT;
-
- ....
-
- or
-
- BINARY LOG:
-
- con1: BEGIN
- con1: INSERT INTO innodb_t VALUES (200);
- con1: COMMIT;
- con2: BEGIN;
- con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
- con2: COMMIT;
-
- Clearly, this may become a problem in STMT mode and setting the statement
- as unsafe will make rows to be written into the binary log in MIXED mode
- and as such the problem will not stand.
-
- In STMT mode, although such statement is classified as unsafe, i.e.
+ 6. The mixed statement is about to update a non-transactional table
+ and read from a temporary transactional table.
+
+ 7. The mixed statement is about to update a non-transactional table
+ and read from a temporary transactional table.
+
+ 8. The mixed statement is about to update a non-transactionala table
+ and read from a temporary non-transactional table.
+
+ 9. The mixed statement is about to update a temporary non-transactional
+ table and update a non-transactional table.
+
+ 10. The mixed statement is about to update a temporary non-transactional
+ table and read from a non-transactional table.
+
+ 11. A statement is about to update a non-transactional table and the
+ option variables.binlog_direct_non_trans_update is OFF.
+
+ The reason for this is that locks acquired may not protected a concurrent
+ transaction of interfering in the current execution and by consequence in
+ the result. In particular, if there is an on-going transaction and a
+ transactional table was already updated, a temporary table must be written
+ to the binary log in the boundaries of the on-going transaction and as
+ such we artificially classify them as transactional.
+ */
+ if (in_multi_stmt_transaction_mode())
+ {
+ my_bool mixed_unsafe= FALSE;
+ my_bool non_trans_unsafe= FALSE;
+
+ /* Case 1. */
+ if (stmt_accessed_table(STMT_WRITES_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 2. */
+ else if (stmt_accessed_table(STMT_WRITES_TEMP_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 3. */
+ else if (stmt_accessed_table(STMT_WRITES_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_NON_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 4. */
+ else if (stmt_accessed_table(STMT_WRITES_TEMP_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_NON_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 5. */
+ else if (stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_TRANS_TABLE) &&
+ tx_isolation < ISO_REPEATABLE_READ)
+ /*
+ By default, InnoDB operates in REPEATABLE READ and with the option
+ --innodb-locks-unsafe-for-binlog disabled. In this case, InnoDB uses
+ next-key locks for searches and index scans, which prevents phantom
+ rows.
+
+ This is scenario is safe for Innodb. However, there are no means to
+ transparently get this information. Therefore, we need to improve this
+ and change the storage engines to report somehow when an execution is
+ safe under an isolation level & binary logging format.
+ */
+ mixed_unsafe= TRUE;
- INSERT INTO myisam_t SELECT * FROM innodb_t;
+ if (trans_has_updated_trans_table(this))
+ {
+ /* Case 6. */
+ if (stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 7. */
+ else if (stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_TEMP_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 8. */
+ else if (stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_TEMP_NON_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 9. */
+ else if (stmt_accessed_table(STMT_WRITES_TEMP_NON_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 10. */
+ else if (stmt_accessed_table(STMT_WRITES_TEMP_NON_TRANS_TABLE) &&
+ stmt_accessed_table(STMT_READS_NON_TRANS_TABLE))
+ mixed_unsafe= TRUE;
+ /* Case 11. */
+ else if (!variables.binlog_direct_non_trans_update &&
+ stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE))
+ non_trans_unsafe= TRUE;
+ }
- there is no enough information to avoid writing it outside the boundaries
- of a transaction. This is not a problem if we are considering snapshot
- isolation level but if we have pure repeatable read or serializable the
- lock history on the slave will be different from the master.
- */
- 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);
+ if (mixed_unsafe)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
+ else if (non_trans_unsafe)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
+ }
/*
If more than one engine is involved in the statement and at
@@ -3930,7 +3928,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
(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)
+ else if (multi_access_engine && flags_access_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 */
@@ -4293,7 +4291,7 @@ CPP_UNNAMED_NS_START
~Row_data_memory()
{
if (m_memory != 0 && m_release_memory_on_destruction)
- my_free((uchar*) m_memory, MYF(MY_WME));
+ my_free(m_memory);
}
/**