1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Merge branch '10.4' into bb-10.4-mdev16188

This commit is contained in:
Igor Babaev
2019-02-03 18:41:18 -08:00
2383 changed files with 85155 additions and 37192 deletions

View File

@ -38,15 +38,14 @@
#include "thr_timer.h"
#include "thr_malloc.h"
#include "log_slow.h" /* LOG_SLOW_DISABLE_... */
#include "sql_digest_stream.h" // sql_digest_state
#include <mysql/psi/mysql_stage.h>
#include <mysql/psi/mysql_statement.h>
#include <mysql/psi/mysql_idle.h>
#include <mysql/psi/mysql_table.h>
#include <mysql_com_server.h>
#include "session_tracker.h"
#include "backup.h"
extern "C"
void set_thd_stage_info(void *thd,
@ -61,8 +60,18 @@ void set_thd_stage_info(void *thd,
#include "my_apc.h"
#include "rpl_gtid.h"
#include "wsrep_mysqld.h"
#include "wsrep_mysqld.h"
#ifdef WITH_WSREP
/* wsrep-lib */
#include "wsrep_client_service.h"
#include "wsrep_client_state.h"
#include "wsrep_mutex.h"
#include "wsrep_condition_variable.h"
class Wsrep_applier_service;
#endif /* WITH_WSREP */
class Reprepare_observer;
class Relay_log_info;
struct rpl_group_info;
@ -156,8 +165,15 @@ enum enum_binlog_row_image {
#define MODE_HIGH_NOT_PRECEDENCE (1ULL << 29)
#define MODE_NO_ENGINE_SUBSTITUTION (1ULL << 30)
#define MODE_PAD_CHAR_TO_FULL_LENGTH (1ULL << 31)
/* SQL mode bits defined above are common for MariaDB and MySQL */
#define MODE_MASK_MYSQL_COMPATIBLE 0xFFFFFFFFULL
/* The following modes are specific to MariaDB */
#define MODE_EMPTY_STRING_IS_NULL (1ULL << 32)
#define MODE_SIMULTANEOUS_ASSIGNMENT (1ULL << 33)
#define MODE_TIME_ROUND_FRACTIONAL (1ULL << 34)
/* The following modes are specific to MySQL */
#define MODE_MYSQL80_TIME_TRUNCATE_FRACTIONAL (1ULL << 32)
/* Bits for different old style modes */
#define OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE (1 << 0)
@ -168,8 +184,6 @@ extern char internal_table_name[2];
extern char empty_c_string[1];
extern MYSQL_PLUGIN_IMPORT const char **errmesg;
extern bool volatile shutdown_in_progress;
extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd);
extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen);
@ -706,10 +720,12 @@ typedef struct system_variables
my_bool wsrep_on;
my_bool wsrep_causal_reads;
uint wsrep_sync_wait;
ulong wsrep_retry_autocommit;
ulonglong wsrep_trx_fragment_size;
ulong wsrep_trx_fragment_unit;
ulong wsrep_OSU_method;
my_bool wsrep_dirty_reads;
uint wsrep_sync_wait;
ulong wsrep_retry_autocommit;
ulong wsrep_OSU_method;
double long_query_time_double, max_statement_time_double;
my_bool pseudo_slave_mode;
@ -1947,42 +1963,22 @@ public:
Global_read_lock()
: m_state(GRL_NONE),
m_mdl_global_shared_lock(NULL),
m_mdl_blocks_commits_lock(NULL)
m_mdl_global_read_lock(NULL)
{}
bool lock_global_read_lock(THD *thd);
void unlock_global_read_lock(THD *thd);
/**
Check if this connection can acquire protection against GRL and
emit error if otherwise.
*/
bool can_acquire_protection() const
{
if (m_state)
{
my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0));
return TRUE;
}
return FALSE;
}
bool make_global_read_lock_block_commit(THD *thd);
bool is_acquired() const { return m_state != GRL_NONE; }
void set_explicit_lock_duration(THD *thd);
private:
enum_grl_state m_state;
/**
In order to acquire the global read lock, the connection must
acquire shared metadata lock in GLOBAL namespace, to prohibit
all DDL.
Global read lock is acquired in two steps:
1. acquire MDL_BACKUP_FTWRL1 in BACKUP namespace to prohibit DDL and DML
2. upgrade to MDL_BACKUP_FTWRL2 to prohibit commits
*/
MDL_ticket *m_mdl_global_shared_lock;
/**
Also in order to acquire the global read lock, the connection
must acquire a shared metadata lock in COMMIT namespace, to
prohibit commits.
*/
MDL_ticket *m_mdl_blocks_commits_lock;
MDL_ticket *m_mdl_global_read_lock;
};
@ -2137,13 +2133,43 @@ struct wait_for_commit
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
/**
A wrapper around thread_count.
It must be specified as a first base class of THD, so that increment is
done before any other THD constructors and decrement - after any other THD
destructors.
*/
struct THD_count
{
THD_count() { thread_count++; }
/**
Decrements thread_count.
Unblocks close_conneciton() if there are no more THD's left.
*/
~THD_count()
{
#ifndef DBUG_OFF
uint32_t t=
#endif
thread_count--;
DBUG_ASSERT(t > 0);
}
};
/**
@class THD
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
*/
class THD :public Statement,
class THD: public THD_count, /* this must be first */
public Statement,
/*
This is to track items changed during execution of a prepared
statement/stored procedure. It's created by
@ -2168,19 +2194,6 @@ private:
inline bool is_conventional() const
{ DBUG_ASSERT(0); return Statement::is_conventional(); }
void dec_thread_count(void)
{
DBUG_ASSERT(thread_count > 0);
thread_safe_decrement32(&thread_count);
signal_thd_deleted();
}
void inc_thread_count(void)
{
thread_safe_increment32(&thread_count);
}
public:
MDL_context mdl_context;
@ -2194,6 +2207,7 @@ public:
rpl_io_thread_info *rpl_io_info;
rpl_sql_thread_info *rpl_sql_info;
} system_thread_info;
MDL_ticket *mdl_backup_ticket, *mdl_backup_lock;
void reset_for_next_command(bool do_clear_errors= 1);
/*
@ -2249,7 +2263,7 @@ public:
- thd->db (used in SHOW PROCESSLIST)
Is locked when THD is deleted.
*/
mysql_mutex_t LOCK_thd_data;
mutable mysql_mutex_t LOCK_thd_data;
/*
Protects:
- kill information
@ -2979,6 +2993,7 @@ public:
uint tmp_table, global_disable_checkpoint;
uint server_status,open_options;
enum enum_thread_type system_thread;
enum backup_stages current_backup_stage;
/*
Current or next transaction isolation level.
When a connection is established, the value is taken from
@ -3209,7 +3224,6 @@ public:
mysql_bin_log.start_union_events() call.
*/
bool unioned_events_trans;
/*
'queries' (actually SP statements) that run under inside this binlog
union have thd->query_id >= first_query_id.
@ -3217,7 +3231,6 @@ public:
query_id_t first_query_id;
} binlog_evt_union;
mysql_cond_t COND_wsrep_thd;
/**
Internal parser state.
Note that since the parser is not re-entrant, we keep only one parser
@ -3300,9 +3313,18 @@ public:
void awake_no_mutex(killed_state state_to_set);
void awake(killed_state state_to_set)
{
bool wsrep_on_local= WSREP_ON;
/*
mutex locking order (LOCK_thd_data - LOCK_thd_kill)) requires
to grab LOCK_thd_data here
*/
if (wsrep_on_local)
mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_lock(&LOCK_thd_kill);
awake_no_mutex(state_to_set);
mysql_mutex_unlock(&LOCK_thd_kill);
if (wsrep_on_local)
mysql_mutex_unlock(&LOCK_thd_data);
}
/** Disconnect the associated communication endpoint. */
@ -3416,6 +3438,15 @@ public:
inline ulong query_start_sec_part()
{ query_start_sec_part_used=1; return start_time_sec_part; }
MYSQL_TIME query_start_TIME();
Timeval query_start_timeval()
{
return Timeval(query_start(), query_start_sec_part());
}
time_round_mode_t temporal_round_mode() const
{
return variables.sql_mode & MODE_TIME_ROUND_FRACTIONAL ?
TIME_FRAC_ROUND : TIME_FRAC_TRUNCATE;
}
private:
struct {
@ -3607,6 +3638,15 @@ public:
{
return server_status & SERVER_STATUS_IN_TRANS;
}
void give_protection_error();
inline bool has_read_only_protection()
{
if (current_backup_stage == BACKUP_FINISHED &&
!global_read_lock.is_acquired())
return FALSE;
give_protection_error();
return TRUE;
}
inline bool fill_derived_tables()
{
return !stmt_arena->is_stmt_prepare() && !lex->only_view_structure();
@ -4414,14 +4454,23 @@ public:
}
void push_warning_truncated_value_for_field(Sql_condition::enum_warning_level
level, const char *type_str,
const char *val, const char *name)
const char *val,
const TABLE_SHARE *s,
const char *name)
{
DBUG_ASSERT(name);
char buff[MYSQL_ERRMSG_SIZE];
CHARSET_INFO *cs= &my_charset_latin1;
const char *db_name= s ? s->db.str : NULL;
const char *table_name= s ? s->error_table_name() : NULL;
if (!db_name)
db_name= "";
if (!table_name)
table_name= "";
cs->cset->snprintf(cs, buff, sizeof(buff),
ER_THD(this, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
type_str, val, name,
type_str, val, db_name, table_name, name,
(ulong) get_stmt_da()->current_row_for_warning());
push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff);
@ -4430,10 +4479,12 @@ public:
bool totally_useless_value,
const char *type_str,
const char *val,
const TABLE_SHARE *s,
const char *field_name)
{
if (field_name)
push_warning_truncated_value_for_field(level, type_str, val, field_name);
push_warning_truncated_value_for_field(level, type_str, val,
s, field_name);
else if (totally_useless_value)
push_warning_wrong_value(level, type_str, val);
else
@ -4481,6 +4532,13 @@ public:
void set_query_id(query_id_t new_query_id)
{
query_id= new_query_id;
#ifdef WITH_WSREP
if (WSREP(this))
{
set_wsrep_next_trx_id(query_id);
WSREP_DEBUG("assigned new next trx id: %lu", wsrep_next_trx_id());
}
#endif /* WITH_WSREP */
}
void set_open_tables(TABLE *open_tables_arg)
{
@ -4736,52 +4794,114 @@ private:
public:
inline ulong wsrep_binlog_format() const
{
return WSREP_FORMAT(variables.binlog_format);
return WSREP_BINLOG_FORMAT(variables.binlog_format);
}
#ifdef WITH_WSREP
const bool wsrep_applier; /* dedicated slave applier thread */
bool wsrep_applier; /* dedicated slave applier thread */
bool wsrep_applier_closing; /* applier marked to close */
bool wsrep_client_thread; /* to identify client threads*/
bool wsrep_PA_safe;
bool wsrep_converted_lock_session;
bool wsrep_apply_toi; /* applier processing in TOI */
enum wsrep_exec_mode wsrep_exec_mode;
query_id_t wsrep_last_query_id;
enum wsrep_query_state wsrep_query_state;
enum wsrep_conflict_state wsrep_conflict_state;
wsrep_trx_meta_t wsrep_trx_meta;
XID wsrep_xid;
/** This flag denotes that record locking should be skipped during INSERT
and gap locking during SELECT. Only used by the streaming replication thread
that only modifies the wsrep_schema.SR table. */
my_bool wsrep_skip_locking;
mysql_cond_t COND_wsrep_thd;
// changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75
uint32 wsrep_rand;
Relay_log_info *wsrep_rli;
rpl_group_info *wsrep_rgi;
wsrep_ws_handle_t wsrep_ws_handle;
bool wsrep_converted_lock_session;
char wsrep_info[128]; /* string for dynamic proc info */
ulong wsrep_retry_counter; // of autocommit
char *wsrep_retry_query;
bool wsrep_PA_safe;
char* wsrep_retry_query;
size_t wsrep_retry_query_len;
enum enum_server_command wsrep_retry_command;
enum wsrep_consistency_check_mode
enum wsrep_consistency_check_mode
wsrep_consistency_check;
std::vector<wsrep::provider::status_variable> wsrep_status_vars;
int wsrep_mysql_replicated;
const char *wsrep_TOI_pre_query; /* a query to apply before
the actual TOI query */
const char* wsrep_TOI_pre_query; /* a query to apply before
the actual TOI query */
size_t wsrep_TOI_pre_query_len;
wsrep_po_handle_t wsrep_po_handle;
size_t wsrep_po_cnt;
#ifdef GTID_SUPPORT
my_bool wsrep_po_in_trans;
rpl_sid wsrep_po_sid;
#endif /* GTID_SUPPORT */
#endif /* GTID_SUPPORT */
void *wsrep_apply_format;
char wsrep_info[128]; /* string for dynamic proc info */
bool wsrep_apply_toi; /* applier processing in TOI */
uchar* wsrep_rbr_buf;
wsrep_gtid_t wsrep_sync_wait_gtid;
// wsrep_gtid_t wsrep_last_written_gtid;
ulong wsrep_affected_rows;
bool wsrep_has_ignored_error;
bool wsrep_replicate_GTID;
/*
When enabled, do not replicate/binlog updates from the current table that's
being processed. At the moment, it is used to keep mysql.gtid_slave_pos
table updates from being replicated to other nodes via galera replication.
*/
bool wsrep_ignore_table;
wsrep_gtid_t wsrep_sync_wait_gtid;
ulong wsrep_affected_rows;
bool wsrep_replicate_GTID;
bool wsrep_skip_wsrep_GTID;
/*
Transaction id:
* m_wsrep_next_trx_id is assigned on the first query after
wsrep_next_trx_id() return WSREP_UNDEFINED_TRX_ID
* Each storage engine must assign value of wsrep_next_trx_id()
when the transaction starts.
* Effective transaction id is returned via wsrep_trx_id()
*/
/*
Return effective transaction id
*/
wsrep_trx_id_t wsrep_trx_id() const
{
return m_wsrep_client_state.transaction().id().get();
}
/*
Set next trx id
*/
void set_wsrep_next_trx_id(query_id_t query_id)
{
m_wsrep_next_trx_id = (wsrep_trx_id_t) query_id;
}
/*
Return next trx id
*/
wsrep_trx_id_t wsrep_next_trx_id() const
{
return m_wsrep_next_trx_id;
}
private:
wsrep_trx_id_t m_wsrep_next_trx_id; /* cast from query_id_t */
/* wsrep-lib */
Wsrep_mutex m_wsrep_mutex;
Wsrep_condition_variable m_wsrep_cond;
Wsrep_client_service m_wsrep_client_service;
Wsrep_client_state m_wsrep_client_state;
public:
Wsrep_client_state& wsrep_cs() { return m_wsrep_client_state; }
const Wsrep_client_state& wsrep_cs() const { return m_wsrep_client_state; }
const wsrep::transaction& wsrep_trx() const
{ return m_wsrep_client_state.transaction(); }
const wsrep::streaming_context& wsrep_sr() const
{ return m_wsrep_client_state.transaction().streaming_context(); }
/* Pointer to applier service for streaming THDs. This is needed to
be able to delete applier service object in case of background
rollback. */
Wsrep_applier_service* wsrep_applier_service;
#endif /* WITH_WSREP */
/* Handling of timeouts for commands */
@ -4830,15 +4950,15 @@ public:
}
/*
Reset current_linfo
Setting current_linfo to 0 needs to be done with LOCK_thread_count to
Setting current_linfo to 0 needs to be done with LOCK_thd_data to
ensure that adjust_linfo_offsets doesn't use a structure that may
be deleted.
*/
inline void reset_current_linfo()
{
mysql_mutex_lock(&LOCK_thread_count);
mysql_mutex_lock(&LOCK_thd_data);
current_linfo= 0;
mysql_mutex_unlock(&LOCK_thread_count);
mysql_mutex_unlock(&LOCK_thd_data);
}
@ -4900,27 +5020,6 @@ public:
}
};
inline void add_to_active_threads(THD *thd)
{
mysql_mutex_lock(&LOCK_thread_count);
threads.append(thd);
mysql_mutex_unlock(&LOCK_thread_count);
}
/*
This should be called when you want to delete a thd that was not
running any queries.
This function will assert that the THD is linked.
*/
inline void unlink_not_visible_thd(THD *thd)
{
thd->assert_linked();
mysql_mutex_lock(&LOCK_thread_count);
thd->unlink();
mysql_mutex_unlock(&LOCK_thread_count);
}
/** A short cut for thd->get_stmt_da()->set_ok_status(). */
inline void
@ -4954,16 +5053,17 @@ my_eof(THD *thd)
(A)->variables.sql_log_bin_off= 0;}
inline date_mode_t sql_mode_for_dates(THD *thd)
inline date_conv_mode_t sql_mode_for_dates(THD *thd)
{
static_assert(C_TIME_FUZZY_DATES == date_mode_t::FUZZY_DATES &&
C_TIME_TIME_ONLY == date_mode_t::TIME_ONLY,
"sql_mode_t and pure C library date flags must be equal");
static_assert((date_conv_mode_t::KNOWN_MODES &
time_round_mode_t::KNOWN_MODES) == 0,
"date_conv_mode_t and time_round_mode_t must use different "
"bit values");
static_assert(MODE_NO_ZERO_DATE == date_mode_t::NO_ZERO_DATE &&
MODE_NO_ZERO_IN_DATE == date_mode_t::NO_ZERO_IN_DATE &&
MODE_INVALID_DATES == date_mode_t::INVALID_DATES,
"sql_mode_t and date_mode_t values must be equal");
return date_mode_t(thd->variables.sql_mode &
return date_conv_mode_t(thd->variables.sql_mode &
(MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE | MODE_INVALID_DATES));
}
@ -5112,6 +5212,14 @@ public:
Currently all intercepting classes derive from select_result_interceptor.
*/
virtual bool is_result_interceptor()=0;
/*
This method is used to distinguish an normal SELECT from the cursor
structure discovery for cursor%ROWTYPE routine variables.
If this method returns "true", then a SELECT execution performs only
all preparation stages, but does not fetch any rows.
*/
virtual bool view_structure_only() const { return false; }
};
@ -5231,9 +5339,13 @@ private:
{
List<sp_variable> *spvar_list;
uint field_count;
bool m_view_structure_only;
bool send_data_to_variable_list(List<sp_variable> &vars, List<Item> &items);
public:
Select_fetch_into_spvars(THD *thd_arg): select_result_interceptor(thd_arg) {}
Select_fetch_into_spvars(THD *thd_arg, bool view_structure_only)
:select_result_interceptor(thd_arg),
m_view_structure_only(view_structure_only)
{}
void reset(THD *thd_arg)
{
select_result_interceptor::reset(thd_arg);
@ -5246,16 +5358,17 @@ private:
virtual bool send_eof() { return FALSE; }
virtual int send_data(List<Item> &items);
virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
virtual bool view_structure_only() const { return m_view_structure_only; }
};
public:
sp_cursor()
:result(NULL),
:result(NULL, false),
m_lex_keeper(NULL),
server_side_cursor(NULL)
{ }
sp_cursor(THD *thd_arg, sp_lex_keeper *lex_keeper)
:result(thd_arg),
sp_cursor(THD *thd_arg, sp_lex_keeper *lex_keeper, bool view_structure_only)
:result(thd_arg, view_structure_only),
m_lex_keeper(lex_keeper),
server_side_cursor(NULL)
{}
@ -5267,8 +5380,6 @@ public:
int open(THD *thd);
int open_view_structure_only(THD *thd);
int close(THD *thd);
my_bool is_open()
@ -6092,6 +6203,10 @@ class multi_delete :public select_result_interceptor
*/
bool error_handled;
public:
// Methods used by ColumnStore
uint get_num_of_tables() const { return num_of_tables; }
TABLE_LIST* get_tables() const { return delete_tables; }
public:
multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables);
~multi_delete();
@ -6272,7 +6387,7 @@ public:
be rolled back or that do not expect any previously metadata
locked tables.
*/
#define CF_IMPLICT_COMMIT_BEGIN (1U << 6)
#define CF_IMPLICIT_COMMIT_BEGIN (1U << 6)
/**
Implicitly commit after the SQL statement.
@ -6290,7 +6405,7 @@ public:
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)
#define CF_AUTO_COMMIT_TRANS (CF_IMPLICIT_COMMIT_BEGIN | CF_IMPLICIT_COMMIT_END)
/**
Diagnostic statement.
@ -6366,6 +6481,14 @@ public:
*/
#define CF_DB_CHANGE (1U << 22)
#ifdef WITH_WSREP
/**
DDL statement that may be subject to error filtering.
*/
#define CF_WSREP_MAY_IGNORE_ERRORS (1U << 23)
#endif /* WITH_WSREP */
/* Bits in server_command_flags */
/**
@ -6807,5 +6930,85 @@ private:
THD *thd;
};
/** THD registry */
class THD_list
{
I_List<THD> threads;
mutable mysql_rwlock_t lock;
public:
/**
Constructor replacement.
Unfortunately we can't use fair constructor to initialize mutex
for two reasons: PFS and embedded. The former can probably be fixed,
the latter can probably be dropped.
*/
void init()
{
mysql_rwlock_init(key_rwlock_THD_list, &lock);
}
/** Destructor replacement. */
void destroy()
{
mysql_rwlock_destroy(&lock);
}
/**
Inserts thread to registry.
@param thd thread
Thread becomes accessible via server_threads.
*/
void insert(THD *thd)
{
mysql_rwlock_wrlock(&lock);
threads.append(thd);
mysql_rwlock_unlock(&lock);
}
/**
Removes thread from registry.
@param thd thread
Thread becomes not accessible via server_threads.
*/
void erase(THD *thd)
{
thd->assert_linked();
mysql_rwlock_wrlock(&lock);
thd->unlink();
mysql_rwlock_unlock(&lock);
}
/**
Iterates registered threads.
@param action called for every element
@param argument opque argument passed to action
@return
@retval 0 iteration completed successfully
@retval 1 iteration was interrupted (action returned 1)
*/
template <typename T> int iterate(my_bool (*action)(THD *thd, T *arg), T *arg= 0)
{
int res= 0;
mysql_rwlock_rdlock(&lock);
I_List_iterator<THD> it(threads);
while (auto tmp= it++)
if ((res= action(tmp, arg)))
break;
mysql_rwlock_unlock(&lock);
return res;
}
};
extern THD_list server_threads;
#endif /* MYSQL_SERVER */
#endif /* SQL_CLASS_INCLUDED */