1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Merge 10.0 to galera-10.0

This commit is contained in:
Jan Lindström
2013-09-03 17:50:36 +03:00
3269 changed files with 156036 additions and 54963 deletions

View File

@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2008, 2013, Monty Program Ab
Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2008, 2013, Monty Program Ab.
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
@@ -63,6 +63,7 @@
#include "debug_sync.h"
#include "sql_parse.h" // is_update_query
#include "sql_callback.h"
#include "lock.h"
#ifdef WITH_WSREP
#include "wsrep_mysqld.h"
#endif
@@ -75,6 +76,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";
/****************************************************************************
@@ -131,6 +134,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),
@@ -586,7 +590,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
}
@@ -685,7 +689,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();
}
@@ -764,7 +768,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);
}
@@ -779,7 +783,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';
@@ -870,11 +874,11 @@ extern "C" wsrep_trx_handle_t* wsrep_thd_trx_handle(THD *thd)
return &thd->wsrep_trx_handle;
}
extern "C"void wsrep_thd_LOCK(THD *thd)
extern "C" void wsrep_thd_LOCK(THD *thd)
{
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
}
extern "C"void wsrep_thd_UNLOCK(THD *thd)
extern "C" void wsrep_thd_UNLOCK(THD *thd)
{
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
}
@@ -927,7 +931,7 @@ extern "C" void wsrep_thd_awake(THD* bf_thd, THD *thd, my_bool signal)
}
}
extern int
extern int
wsrep_trx_order_before(void *thd1, void *thd2)
{
if (((THD*)thd1)->wsrep_trx_seqno < ((THD*)thd2)->wsrep_trx_seqno) {
@@ -971,9 +975,9 @@ wsrep_trx_is_aborting(void *thd_ptr)
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) ||
@@ -1000,8 +1004,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),
@@ -1026,7 +1028,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;
@@ -1038,8 +1041,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
@@ -1096,6 +1099,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;
@@ -1229,9 +1233,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)
{
@@ -1268,7 +1272,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);
}
@@ -1284,7 +1288,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;
}
@@ -1294,7 +1298,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);
}
@@ -1310,7 +1314,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;
}
@@ -1324,7 +1328,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;
}
@@ -1343,24 +1347,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
@@ -1374,24 +1379,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);
@@ -1400,14 +1405,14 @@ 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)
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);
}
}
@@ -1421,7 +1426,7 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno,
if (!(is_fatal_error && (sql_errno == EE_OUTOFMEMORY ||
sql_errno == ER_OUTOFMEMORY)))
{
cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg);
cond= da->push_warning(this, sql_errno, sqlstate, level, msg);
}
DBUG_RETURN(cond);
}
@@ -1534,6 +1539,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));
#ifdef WITH_WSREP
@@ -1682,6 +1688,8 @@ void THD::cleanup(void)
}
#endif
mysql_ha_cleanup(this);
close_temporary_tables(this);
transaction.xid_state.xa_state= XA_NOTR;
@@ -1689,7 +1697,6 @@ void THD::cleanup(void)
xid_cache_delete(&transaction.xid_state);
locked_tables_list.unlock_locked_tables(this);
mysql_ha_cleanup(this);
DBUG_ASSERT(open_tables == NULL);
/*
@@ -1745,7 +1752,6 @@ THD::~THD()
/* Ensure that no one is using THD */
mysql_mutex_lock(&LOCK_thd_data);
mysys_var=0; // Safety (shouldn't be needed)
mysql_mutex_unlock(&LOCK_thd_data);
#ifdef WITH_WSREP
@@ -1770,7 +1776,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;
@@ -1794,12 +1799,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);
@@ -1990,8 +1997,8 @@ void THD::awake(killed_state state_to_set)
mysql_mutex_unlock(mysys_var->current_mutex);
break;
}
my_sleep(1000000L / WAIT_FOR_KILL_TRY_TIMES);
}
my_sleep(1000000L / WAIT_FOR_KILL_TRY_TIMES);
}
mysql_mutex_unlock(&mysys_var->mutex);
}
@@ -2032,6 +2039,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.
@@ -2182,6 +2229,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 */
@@ -2902,7 +2957,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));
}
@@ -2933,7 +2988,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;
}
@@ -3016,7 +3071,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,
@@ -3027,7 +3082,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));
}
@@ -3062,7 +3117,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) &&
@@ -3803,7 +3858,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
@@ -3974,6 +4029,7 @@ void Security_context::init()
void Security_context::destroy()
{
DBUG_PRINT("info", ("freeing security context"));
// If not pointer to constant
if (host != my_localhost)
{
@@ -4207,7 +4263,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
@@ -4398,6 +4454,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
@@ -4633,7 +4724,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
}
@@ -4641,7 +4732,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
}
@@ -4649,7 +4740,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
}
@@ -4657,7 +4748,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
}
@@ -4665,7 +4756,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
}
@@ -4673,7 +4764,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
}
@@ -4681,7 +4772,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
}
@@ -4689,7 +4780,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
}
@@ -4697,7 +4788,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
}
@@ -4705,7 +4796,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
}
@@ -4713,7 +4804,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
}
@@ -4721,7 +4812,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
}
@@ -4729,7 +4820,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
}
@@ -4737,7 +4828,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
}
@@ -4750,7 +4841,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
}
@@ -5063,6 +5154,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
@@ -5105,6 +5198,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
{
@@ -5127,14 +5242,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 && !table->table->s->is_gtid_slave_pos)
{
/*
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 !=
@@ -5161,7 +5300,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
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.tmp_table()))
{
my_bool trans= table->table->file->has_transactions();
@@ -5317,6 +5456,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);
@@ -5324,6 +5487,46 @@ int THD::decide_logging_format(TABLE_LIST *tables)
DBUG_PRINT("info", ("decision: logging in %s format",
is_current_stmt_binlog_format_row() ?
"ROW" : "STATEMENT"));
if (variables.binlog_format == BINLOG_FORMAT_ROW &&
(lex->sql_command == SQLCOM_UPDATE ||
lex->sql_command == SQLCOM_UPDATE_MULTI ||
lex->sql_command == SQLCOM_DELETE ||
lex->sql_command == SQLCOM_DELETE_MULTI))
{
String table_names;
/*
Generate a warning for UPDATE/DELETE statements that modify a
BLACKHOLE table, as row events are not logged in row format.
*/
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
if (table->placeholder())
continue;
if (table->table->file->ht->db_type == DB_TYPE_BLACKHOLE_DB &&
table->lock_type >= TL_WRITE_ALLOW_WRITE)
{
table_names.append(table->table_name);
table_names.append(",");
}
}
if (!table_names.is_empty())
{
bool is_update= (lex->sql_command == SQLCOM_UPDATE ||
lex->sql_command == SQLCOM_UPDATE_MULTI);
/*
Replace the last ',' with '.' for table_names
*/
table_names.replace(table_names.length()-1, 1, ".", 1);
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. "
"Table(s): '%-.192s'",
is_update ? "UPDATE" : "DELETE",
table_names.c_ptr());
}
}
}
#ifndef DBUG_OFF
else
@@ -5918,7 +6121,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]));
@@ -5972,6 +6175,15 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
#else
DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
#endif
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