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.cc316
1 files changed, 245 insertions, 71 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 4fc1769ba1f..c9f07c4d036 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -63,6 +63,7 @@
#include "debug_sync.h"
#include "sql_parse.h" // is_update_query
#include "sql_callback.h"
+#include "lock.h"
#include "sql_connect.h"
/*
@@ -72,6 +73,8 @@
char internal_table_name[2]= "*";
char empty_c_string[1]= {0}; /* used for not defined db */
+LEX_STRING EMPTY_STR= { (char *) "", 0 };
+
const char * const THD::DEFAULT_WHERE= "field list";
/****************************************************************************
@@ -128,6 +131,7 @@ Key::Key(const Key &rhs, MEM_ROOT *mem_root)
Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
:Key(rhs,mem_root),
+ ref_db(rhs.ref_db),
ref_table(rhs.ref_table),
ref_columns(rhs.ref_columns,mem_root),
delete_opt(rhs.delete_opt),
@@ -583,7 +587,7 @@ void THD::enter_stage(const PSI_stage_info *new_stage,
proc_info= msg;
#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_CALL(set_thread_state)(msg);
+ PSI_THREAD_CALL(set_thread_state)(msg);
MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line);
#endif
}
@@ -682,7 +686,7 @@ int thd_tx_is_read_only(const THD *thd)
extern "C"
void thd_inc_row_count(THD *thd)
{
- thd->warning_info->inc_current_row_for_warning();
+ thd->get_stmt_da()->inc_current_row_for_warning();
}
@@ -761,7 +765,7 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
if (max_query_len < 1)
len= thd->query_length();
else
- len= min(thd->query_length(), max_query_len);
+ len= MY_MIN(thd->query_length(), max_query_len);
str.append('\n');
str.append(thd->query(), len);
}
@@ -776,7 +780,7 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
was reallocated to a larger buffer to be able to fit.
*/
DBUG_ASSERT(buffer != NULL);
- length= min(str.length(), length-1);
+ length= MY_MIN(str.length(), length-1);
memcpy(buffer, str.c_ptr_quick(), length);
/* Make sure that the new string is null terminated */
buffer[length]= '\0';
@@ -801,9 +805,9 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
bool Drop_table_error_handler::handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
+ Sql_condition::enum_warning_level level,
const char* msg,
- MYSQL_ERROR ** cond_hdl)
+ Sql_condition ** cond_hdl)
{
*cond_hdl= NULL;
return ((sql_errno == EE_DELETE && my_errno == ENOENT) ||
@@ -826,8 +830,6 @@ THD::THD()
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
m_examined_row_count(0),
accessed_rows_and_keys(0),
- warning_info(&main_warning_info),
- stmt_da(&main_da),
m_statement_psi(NULL),
m_idle_psi(NULL),
m_server_idle(false),
@@ -847,7 +849,8 @@ THD::THD()
#if defined(ENABLED_DEBUG_SYNC)
debug_sync_control(0),
#endif /* defined(ENABLED_DEBUG_SYNC) */
- main_warning_info(0, false, false)
+ main_da(0, false, false),
+ m_stmt_da(&main_da)
{
ulong tmp;
@@ -859,8 +862,8 @@ THD::THD()
THD *old_THR_THD= current_thd;
set_current_thd(this);
status_var.memory_used= 0;
+ main_da.init();
- main_warning_info.init();
/*
Pass nominal parameters to init_alloc_root only to ensure that
the destructor works OK in case of an error. The main_mem_root
@@ -917,6 +920,7 @@ THD::THD()
mysys_var=0;
binlog_evt_union.do_union= FALSE;
enable_slow_log= 0;
+ durability_property= HA_REGULAR_DURABILITY;
#ifndef DBUG_OFF
dbug_sentry=THD_SENTRY_MAGIC;
@@ -1026,9 +1030,9 @@ void THD::push_internal_handler(Internal_error_handler *handler)
bool THD::handle_condition(uint sql_errno,
const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
+ Sql_condition::enum_warning_level level,
const char* msg,
- MYSQL_ERROR ** cond_hdl)
+ Sql_condition ** cond_hdl)
{
if (!m_internal_handler)
{
@@ -1065,7 +1069,7 @@ void THD::raise_error(uint sql_errno)
const char* msg= ER(sql_errno);
(void) raise_condition(sql_errno,
NULL,
- MYSQL_ERROR::WARN_LEVEL_ERROR,
+ Sql_condition::WARN_LEVEL_ERROR,
msg);
}
@@ -1081,7 +1085,7 @@ void THD::raise_error_printf(uint sql_errno, ...)
va_end(args);
(void) raise_condition(sql_errno,
NULL,
- MYSQL_ERROR::WARN_LEVEL_ERROR,
+ Sql_condition::WARN_LEVEL_ERROR,
ebuff);
DBUG_VOID_RETURN;
}
@@ -1091,7 +1095,7 @@ void THD::raise_warning(uint sql_errno)
const char* msg= ER(sql_errno);
(void) raise_condition(sql_errno,
NULL,
- MYSQL_ERROR::WARN_LEVEL_WARN,
+ Sql_condition::WARN_LEVEL_WARN,
msg);
}
@@ -1107,7 +1111,7 @@ void THD::raise_warning_printf(uint sql_errno, ...)
va_end(args);
(void) raise_condition(sql_errno,
NULL,
- MYSQL_ERROR::WARN_LEVEL_WARN,
+ Sql_condition::WARN_LEVEL_WARN,
ebuff);
DBUG_VOID_RETURN;
}
@@ -1121,7 +1125,7 @@ void THD::raise_note(uint sql_errno)
const char* msg= ER(sql_errno);
(void) raise_condition(sql_errno,
NULL,
- MYSQL_ERROR::WARN_LEVEL_NOTE,
+ Sql_condition::WARN_LEVEL_NOTE,
msg);
DBUG_VOID_RETURN;
}
@@ -1140,24 +1144,25 @@ void THD::raise_note_printf(uint sql_errno, ...)
va_end(args);
(void) raise_condition(sql_errno,
NULL,
- MYSQL_ERROR::WARN_LEVEL_NOTE,
+ Sql_condition::WARN_LEVEL_NOTE,
ebuff);
DBUG_VOID_RETURN;
}
-MYSQL_ERROR* THD::raise_condition(uint sql_errno,
+Sql_condition* THD::raise_condition(uint sql_errno,
const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
+ Sql_condition::enum_warning_level level,
const char* msg)
{
- MYSQL_ERROR *cond= NULL;
+ Diagnostics_area *da= get_stmt_da();
+ Sql_condition *cond= NULL;
DBUG_ENTER("THD::raise_condition");
if (!(variables.option_bits & OPTION_SQL_NOTES) &&
- (level == MYSQL_ERROR::WARN_LEVEL_NOTE))
+ (level == Sql_condition::WARN_LEVEL_NOTE))
DBUG_RETURN(NULL);
- warning_info->opt_clear_warning_info(query_id);
+ da->opt_clear_warning_info(query_id);
/*
TODO: replace by DBUG_ASSERT(sql_errno != 0) once all bugs similar to
@@ -1171,24 +1176,24 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno,
if (sqlstate == NULL)
sqlstate= mysql_errno_to_sqlstate(sql_errno);
- if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
+ if ((level == Sql_condition::WARN_LEVEL_WARN) &&
really_abort_on_warning())
{
/*
FIXME:
push_warning and strict SQL_MODE case.
*/
- level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ level= Sql_condition::WARN_LEVEL_ERROR;
killed= KILL_BAD_DATA;
}
switch (level)
{
- case MYSQL_ERROR::WARN_LEVEL_NOTE:
- case MYSQL_ERROR::WARN_LEVEL_WARN:
+ case Sql_condition::WARN_LEVEL_NOTE:
+ case Sql_condition::WARN_LEVEL_WARN:
got_warning= 1;
break;
- case MYSQL_ERROR::WARN_LEVEL_ERROR:
+ case Sql_condition::WARN_LEVEL_ERROR:
break;
default:
DBUG_ASSERT(FALSE);
@@ -1197,29 +1202,31 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno,
if (handle_condition(sql_errno, sqlstate, level, msg, &cond))
DBUG_RETURN(cond);
- if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
+ /*
+ Avoid pushing a condition for fatal out of memory errors as this will
+ require memory allocation and therefore might fail. Non fatal out of
+ memory errors can occur if raised by SIGNAL/RESIGNAL statement.
+ */
+ if (!(is_fatal_error && (sql_errno == EE_OUTOFMEMORY ||
+ sql_errno == ER_OUTOFMEMORY)))
+ {
+ cond= da->push_warning(this, sql_errno, sqlstate, level, msg);
+ }
+
+
+ if (level == Sql_condition::WARN_LEVEL_ERROR)
{
is_slave_error= 1; // needed to catch query errors during replication
- if (! stmt_da->is_error())
+ if (!da->is_error())
{
set_row_count_func(-1);
- stmt_da->set_error_status(this, sql_errno, msg, sqlstate);
+ da->set_error_status(sql_errno, msg, sqlstate, cond);
}
}
query_cache_abort(&query_cache_tls);
- /*
- Avoid pushing a condition for fatal out of memory errors as this will
- require memory allocation and therefore might fail. Non fatal out of
- memory errors can occur if raised by SIGNAL/RESIGNAL statement.
- */
- if (!(is_fatal_error && (sql_errno == EE_OUTOFMEMORY ||
- sql_errno == ER_OUTOFMEMORY)))
- {
- cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg);
- }
DBUG_RETURN(cond);
}
@@ -1331,6 +1338,7 @@ void THD::init(void)
tx_read_only= variables.tx_read_only;
update_charset();
reset_current_stmt_binlog_format_row();
+ reset_binlog_local_stmt_filter();
set_status_var_init();
bzero((char *) &org_status_var, sizeof(org_status_var));
@@ -1546,7 +1554,6 @@ THD::~THD()
mysql_audit_release(this);
plugin_thdvar_cleanup(this);
- DBUG_PRINT("info", ("freeing security context"));
main_security_ctx.destroy();
my_free(db);
db= NULL;
@@ -1570,12 +1577,14 @@ THD::~THD()
#endif
free_root(&main_mem_root, MYF(0));
- main_warning_info.free_memory();
+ main_da.free_memory();
if (status_var.memory_used != 0)
{
DBUG_PRINT("error", ("memory_used: %lld", status_var.memory_used));
SAFEMALLOC_REPORT_MEMORY(my_thread_dbug_id());
+#ifdef ENABLE_BEFORE_END_OF_MERGE_QQ
DBUG_ASSERT(status_var.memory_used == 0); // Ensure everything is freed
+#endif
}
set_current_thd(orig_thd);
@@ -1805,6 +1814,46 @@ void THD::disconnect()
}
+bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
+ bool needs_thr_lock_abort)
+{
+ THD *in_use= ctx_in_use->get_thd();
+ bool signalled= FALSE;
+
+ if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
+ !in_use->killed)
+ {
+ in_use->killed= KILL_CONNECTION;
+ mysql_mutex_lock(&in_use->mysys_var->mutex);
+ if (in_use->mysys_var->current_cond)
+ mysql_cond_broadcast(in_use->mysys_var->current_cond);
+ mysql_mutex_unlock(&in_use->mysys_var->mutex);
+ signalled= TRUE;
+ }
+
+ if (needs_thr_lock_abort)
+ {
+ mysql_mutex_lock(&in_use->LOCK_thd_data);
+ for (TABLE *thd_table= in_use->open_tables;
+ thd_table ;
+ thd_table= thd_table->next)
+ {
+ /*
+ Check for TABLE::needs_reopen() is needed since in some places we call
+ handler::close() for table instance (and set TABLE::db_stat to 0)
+ and do not remove such instances from the THD::open_tables
+ for some time, during which other thread can see those instances
+ (e.g. see partitioning code).
+ */
+ if (!thd_table->needs_reopen())
+ signalled|= mysql_lock_abort_for_thread(this, thd_table);
+ }
+ mysql_mutex_unlock(&in_use->LOCK_thd_data);
+ }
+ return signalled;
+}
+
+
/*
Get error number for killed state
Note that the error message can't have any parameters.
@@ -1955,6 +2004,14 @@ void THD::cleanup_after_query()
auto_inc_intervals_forced.empty();
#endif
}
+ /*
+ Forget the binlog stmt filter for the next query.
+ There are some code paths that:
+ - do not call THD::decide_logging_format()
+ - do call THD::binlog_query(),
+ making this reset necessary.
+ */
+ reset_binlog_local_stmt_filter();
if (first_successful_insert_id_in_cur_stmt > 0)
{
/* set what LAST_INSERT_ID() will return */
@@ -2661,7 +2718,7 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
Non-ASCII separator arguments are not fully supported
*/
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED,
ER(WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED));
}
@@ -2692,7 +2749,7 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
(exchange->opt_enclosed && non_string_results &&
field_term_length && strchr(NUMERIC_CHARS, field_term_char)))
{
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_AMBIGUOUS_FIELD_TERM, ER(ER_AMBIGUOUS_FIELD_TERM));
is_ambiguous_field_term= TRUE;
}
@@ -2775,7 +2832,7 @@ int select_export::send_data(List<Item> &items)
convert_to_printable(printable_buff, sizeof(printable_buff),
error_pos, res->ptr() + res->length() - error_pos,
res->charset(), 6);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
"string", printable_buff,
@@ -2786,7 +2843,7 @@ int select_export::send_data(List<Item> &items)
/*
result is longer than UINT_MAX32 and doesn't fit into String
*/
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED),
item->full_name(), static_cast<long>(row_count));
}
@@ -2821,7 +2878,7 @@ int select_export::send_data(List<Item> &items)
else
{
if (fixed_row_size)
- used_length=min(res->length(),item->max_length);
+ used_length=MY_MIN(res->length(),item->max_length);
else
used_length=res->length();
if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
@@ -3562,7 +3619,7 @@ int select_dumpvar::send_data(List<Item> &items)
bool select_dumpvar::send_eof()
{
if (! row_count)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
/*
Don't send EOF if we're in error condition (which implies we've already
@@ -3733,6 +3790,7 @@ void Security_context::init()
void Security_context::destroy()
{
+ DBUG_PRINT("info", ("freeing security context"));
// If not pointer to constant
if (host != my_localhost)
{
@@ -3966,7 +4024,7 @@ static void thd_send_progress(THD *thd)
ulonglong report_time= my_interval_timer();
if (report_time > thd->progress.next_report_time)
{
- uint seconds_to_next= max(thd->variables.progress_report_time,
+ uint seconds_to_next= MY_MAX(thd->variables.progress_report_time,
global_system_variables.progress_report_time);
if (seconds_to_next == 0) // Turned off
seconds_to_next= 1; // Check again after 1 second
@@ -4152,6 +4210,41 @@ extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd)
}
+extern "C" enum durability_properties thd_get_durability_property(const MYSQL_THD thd)
+{
+ enum durability_properties ret= HA_REGULAR_DURABILITY;
+
+ if (thd != NULL)
+ ret= thd->durability_property;
+
+ return ret;
+}
+
+/** Get the auto_increment_offset auto_increment_increment.
+Needed by InnoDB.
+@param thd Thread object
+@param off auto_increment_offset
+@param inc auto_increment_increment */
+extern "C" void thd_get_autoinc(const MYSQL_THD thd, ulong* off, ulong* inc)
+{
+ *off = thd->variables.auto_increment_offset;
+ *inc = thd->variables.auto_increment_increment;
+}
+
+
+/**
+ Is strict sql_mode set.
+ Needed by InnoDB.
+ @param thd Thread object
+ @return True if sql_mode has strict mode (all or trans).
+ @retval true sql_mode has strict mode (all or trans).
+ @retval false sql_mode has not strict mode (all or trans).
+*/
+extern "C" bool thd_is_strict_mode(const MYSQL_THD thd)
+{
+ return thd->is_strict_mode();
+}
+
/*
Interface for MySQL Server, plugins and storage engines to report
@@ -4387,7 +4480,7 @@ void THD::inc_status_created_tmp_disk_tables()
{
status_var_increment(status_var.created_tmp_disk_tables_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_created_tmp_disk_tables)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_created_tmp_disk_tables)(m_statement_psi, 1);
#endif
}
@@ -4395,7 +4488,7 @@ void THD::inc_status_created_tmp_tables()
{
status_var_increment(status_var.created_tmp_tables_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_created_tmp_tables)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_created_tmp_tables)(m_statement_psi, 1);
#endif
}
@@ -4403,7 +4496,7 @@ void THD::inc_status_select_full_join()
{
status_var_increment(status_var.select_full_join_count_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_select_full_join)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_select_full_join)(m_statement_psi, 1);
#endif
}
@@ -4411,7 +4504,7 @@ void THD::inc_status_select_full_range_join()
{
status_var_increment(status_var.select_full_range_join_count_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_select_full_range_join)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_select_full_range_join)(m_statement_psi, 1);
#endif
}
@@ -4419,7 +4512,7 @@ void THD::inc_status_select_range()
{
status_var_increment(status_var.select_range_count_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_select_range)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_select_range)(m_statement_psi, 1);
#endif
}
@@ -4427,7 +4520,7 @@ void THD::inc_status_select_range_check()
{
status_var_increment(status_var.select_range_check_count_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_select_range_check)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_select_range_check)(m_statement_psi, 1);
#endif
}
@@ -4435,7 +4528,7 @@ void THD::inc_status_select_scan()
{
status_var_increment(status_var.select_scan_count_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_select_scan)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_select_scan)(m_statement_psi, 1);
#endif
}
@@ -4443,7 +4536,7 @@ void THD::inc_status_sort_merge_passes()
{
status_var_increment(status_var.filesort_merge_passes_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_sort_merge_passes)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_sort_merge_passes)(m_statement_psi, 1);
#endif
}
@@ -4451,7 +4544,7 @@ void THD::inc_status_sort_range()
{
status_var_increment(status_var.filesort_range_count_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_sort_range)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_sort_range)(m_statement_psi, 1);
#endif
}
@@ -4459,7 +4552,7 @@ void THD::inc_status_sort_rows(ha_rows count)
{
statistic_add(status_var.filesort_rows_, count, &LOCK_status);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_sort_rows)(m_statement_psi, count);
+ PSI_STATEMENT_CALL(inc_statement_sort_rows)(m_statement_psi, count);
#endif
}
@@ -4467,7 +4560,7 @@ void THD::inc_status_sort_scan()
{
status_var_increment(status_var.filesort_scan_count_);
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(inc_statement_sort_scan)(m_statement_psi, 1);
+ PSI_STATEMENT_CALL(inc_statement_sort_scan)(m_statement_psi, 1);
#endif
}
@@ -4475,7 +4568,7 @@ void THD::set_status_no_index_used()
{
server_status|= SERVER_QUERY_NO_INDEX_USED;
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(set_statement_no_index_used)(m_statement_psi);
+ PSI_STATEMENT_CALL(set_statement_no_index_used)(m_statement_psi);
#endif
}
@@ -4483,7 +4576,7 @@ void THD::set_status_no_good_index_used()
{
server_status|= SERVER_QUERY_NO_GOOD_INDEX_USED;
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- PSI_CALL(set_statement_no_good_index_used)(m_statement_psi);
+ PSI_STATEMENT_CALL(set_statement_no_good_index_used)(m_statement_psi);
#endif
}
@@ -4491,7 +4584,7 @@ void THD::set_command(enum enum_server_command command)
{
m_command= command;
#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_CALL(set_thread_command)(m_command);
+ PSI_STATEMENT_CALL(set_thread_command)(m_command);
#endif
}
@@ -4504,7 +4597,7 @@ void THD::set_query(const CSET_STRING &string_arg)
mysql_mutex_unlock(&LOCK_thd_data);
#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_CALL(set_thread_info)(query(), query_length());
+ PSI_THREAD_CALL(set_thread_info)(query(), query_length());
#endif
}
@@ -4817,6 +4910,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
lex->get_stmt_unsafe_flags()));
+ reset_binlog_local_stmt_filter();
+
/*
We should not decide logging format if the binlog is closed or
binlogging is off, or if the statement is filtered out from the
@@ -4859,6 +4954,28 @@ int THD::decide_logging_format(TABLE_LIST *tables)
A pointer to a previous table that was accessed.
*/
TABLE* prev_access_table= NULL;
+ /**
+ The number of tables used in the current statement,
+ that should be replicated.
+ */
+ uint replicated_tables_count= 0;
+ /**
+ The number of tables written to in the current statement,
+ that should not be replicated.
+ A table should not be replicated when it is considered
+ 'local' to a MySQL instance.
+ Currently, these tables are:
+ - mysql.slow_log
+ - mysql.general_log
+ - mysql.slave_relay_log_info
+ - mysql.slave_master_info
+ - mysql.slave_worker_info
+ - performance_schema.*
+ - TODO: information_schema.*
+ In practice, from this list, only performance_schema.* tables
+ are written to by user queries.
+ */
+ uint non_replicated_tables_count= 0;
#ifndef DBUG_OFF
{
@@ -4881,14 +4998,38 @@ int THD::decide_logging_format(TABLE_LIST *tables)
if (table->placeholder())
continue;
- if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE ||
- table->table->s->table_category == TABLE_CATEGORY_LOG)
- 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->table->no_replicate)
+ {
+ /*
+ The statement uses a table that is not replicated.
+ The following properties about the table:
+ - persistent / transient
+ - transactional / non transactional
+ - temporary / permanent
+ - read or write
+ - multiple engines involved because of this table
+ are not relevant, as this table is completely ignored.
+ Because the statement uses a non replicated table,
+ using STATEMENT format in the binlog is impossible.
+ Either this statement will be discarded entirely,
+ or it will be logged (possibly partially) in ROW format.
+ */
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
+
+ if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ non_replicated_tables_count++;
+ continue;
+ }
+ }
+
+ replicated_tables_count++;
+
if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
{
if (prev_write_table && prev_write_table->file->ht !=
@@ -5064,6 +5205,30 @@ int THD::decide_logging_format(TABLE_LIST *tables)
}
}
+ if (non_replicated_tables_count > 0)
+ {
+ if ((replicated_tables_count == 0) || ! is_write)
+ {
+ DBUG_PRINT("info", ("decision: no logging, no replicated table affected"));
+ set_binlog_local_stmt_filter();
+ }
+ else
+ {
+ if (! is_current_stmt_binlog_format_row())
+ {
+ my_error((error= ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES), MYF(0));
+ }
+ else
+ {
+ clear_binlog_local_stmt_filter();
+ }
+ }
+ }
+ else
+ {
+ clear_binlog_local_stmt_filter();
+ }
+
if (error) {
DBUG_PRINT("info", ("decision: no logging since an error was generated"));
DBUG_RETURN(-1);
@@ -5102,7 +5267,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
Replace the last ',' with '.' for table_names
*/
table_names.replace(table_names.length()-1, 1, ".", 1);
- push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(this, Sql_condition::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR,
"Row events are not logged for %s statements "
"that modify BLACKHOLE tables in row format. "
@@ -5679,7 +5844,7 @@ void THD::issue_unsafe_warnings()
{
if ((unsafe_type_flags & (1 << unsafe_type)) != 0)
{
- push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning_printf(this, Sql_condition::WARN_LEVEL_NOTE,
ER_BINLOG_UNSAFE_STATEMENT,
ER(ER_BINLOG_UNSAFE_STATEMENT),
ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
@@ -5729,6 +5894,15 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
show_query_type(qtype), (int) query_len, query_arg));
DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
+ if (get_binlog_local_stmt_filter() == BINLOG_FILTER_SET)
+ {
+ /*
+ The current statement is to be ignored, and not written to
+ the binlog. Do not call issue_unsafe_warnings().
+ */
+ DBUG_RETURN(0);
+ }
+
/*
If we are not in prelocked mode, mysql_unlock_tables() will be
called after this binlog_query(), so we have to flush the pending