Commit f5c3ad19 authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-16470 - Session user variables tracker

Based on contribution by Dapeng Huang.
parent ad77e3ac
......@@ -108,6 +108,7 @@ enum enum_session_state_type
SESSION_TRACK_GTIDS,
SESSION_TRACK_TRANSACTION_CHARACTERISTICS,
SESSION_TRACK_TRANSACTION_STATE,
SESSION_TRACK_USER_VARIABLES,
SESSION_TRACK_always_at_the_end
};
extern "C" {
......
......@@ -601,6 +601,7 @@ enum enum_session_state_type
SESSION_TRACK_GTIDS,
SESSION_TRACK_TRANSACTION_CHARACTERISTICS, /* Transaction chistics */
SESSION_TRACK_TRANSACTION_STATE, /* Transaction state */
SESSION_TRACK_USER_VARIABLES,
SESSION_TRACK_always_at_the_end /* must be last */
};
......
......@@ -1117,6 +1117,8 @@ The following specify which files/extra groups are read (specified before remain
characteristics (isolation level, read only/read
write,snapshot - but not any work done / data modified
within the transaction).
--session-track-user-variables
Track changes to user variables.
--show-slave-auth-info
Show user and password in SHOW SLAVE HOSTS on this
master.
......@@ -1712,6 +1714,7 @@ session-track-schema TRUE
session-track-state-change FALSE
session-track-system-variables autocommit,character_set_client,character_set_connection,character_set_results,time_zone
session-track-transaction-info OFF
session-track-user-variables FALSE
show-slave-auth-info FALSE
silent-startup FALSE
skip-grant-tables TRUE
......
......@@ -29,3 +29,13 @@ SET NAMES 'utf8';
# tracking info off once
SET NAMES 'big5';
SET @@session.session_track_system_variables= default;
#
# MDEV-16470 - Session user variables tracker
#
SET @@session.session_track_user_variables=1;
SET @a=1;
SET @b=NULL;
SELECT @c:=10;
@c:=10
10
SET @@session.session_track_user_variables=0;
......@@ -23,3 +23,14 @@ SET NAMES 'big5';
--disable_session_track_info
SET @@session.session_track_system_variables= default;
--echo #
--echo # MDEV-16470 - Session user variables tracker
--echo #
SET @@session.session_track_user_variables=1;
--enable_session_track_info
SET @a=1;
SET @b=NULL;
SELECT @c:=10;
--disable_session_track_info
SET @@session.session_track_user_variables=0;
......@@ -12,19 +12,13 @@ SELECT @@session.session_track_system_variables;
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
# via INFORMATION_SCHEMA.GLOBAL_VARIABLES
SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track%' ORDER BY VARIABLE_NAME;
SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track_system_variables' ORDER BY VARIABLE_NAME;
VARIABLE_NAME VARIABLE_VALUE
SESSION_TRACK_SCHEMA ON
SESSION_TRACK_STATE_CHANGE OFF
SESSION_TRACK_SYSTEM_VARIABLES autocommit,character_set_client,character_set_connection,character_set_results,time_zone
SESSION_TRACK_TRANSACTION_INFO OFF
# via INFORMATION_SCHEMA.SESSION_VARIABLES
SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track%' ORDER BY VARIABLE_NAME;
SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track_system_variables' ORDER BY VARIABLE_NAME;
VARIABLE_NAME VARIABLE_VALUE
SESSION_TRACK_SCHEMA ON
SESSION_TRACK_STATE_CHANGE OFF
SESSION_TRACK_SYSTEM_VARIABLES autocommit,character_set_client,character_set_connection,character_set_results,time_zone
SESSION_TRACK_TRANSACTION_INFO OFF
SET @global_saved_tmp = @@global.session_track_system_variables;
# Altering global variable's value
......
......@@ -3453,6 +3453,16 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,STATE,CHARACTERISTICS
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME SESSION_TRACK_USER_VARIABLES
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Track changes to user variables.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME SKIP_EXTERNAL_LOCKING
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BOOLEAN
......
......@@ -12,10 +12,10 @@ SELECT @@session.session_track_system_variables;
--echo
--echo # via INFORMATION_SCHEMA.GLOBAL_VARIABLES
SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track%' ORDER BY VARIABLE_NAME;
SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track_system_variables' ORDER BY VARIABLE_NAME;
--echo # via INFORMATION_SCHEMA.SESSION_VARIABLES
SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track%' ORDER BY VARIABLE_NAME;
SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track_system_variables' ORDER BY VARIABLE_NAME;
# Save the global value to be used to restore the original value.
SET @global_saved_tmp = @@global.session_track_system_variables;
......
......@@ -4671,6 +4671,10 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
entry->unsigned_flag= unsigned_arg;
}
entry->type=type;
#ifndef EMBEDDED_LIBRARY
THD *thd= current_thd;
thd->session_tracker.user_variables.mark_as_changed(thd, entry);
#endif
return 0;
}
......@@ -4760,7 +4764,7 @@ longlong user_var_entry::val_int(bool *null_value) const
/** Get the value of a variable as a string. */
String *user_var_entry::val_str(bool *null_value, String *str,
uint decimals)
uint decimals) const
{
if ((*null_value= (value == 0)))
return (String*) 0;
......
......@@ -16,7 +16,6 @@
#include "sql_plugin.h"
#include "hash.h"
#include "table.h"
#include "rpl_gtid.h"
#include "sql_class.h"
......@@ -1182,6 +1181,38 @@ bool Session_state_change_tracker::store(THD *thd, String *buf)
return false;
}
bool User_variables_tracker::update(THD *thd, set_var *)
{
m_enabled= thd->variables.session_track_user_variables;
return false;
}
bool User_variables_tracker::store(THD *thd, String *buf)
{
for (ulong i= 0; i < m_changed_user_variables.size(); i++)
{
auto var= m_changed_user_variables.at(i);
String value_str;
bool null_value;
var->val_str(&null_value, &value_str, DECIMAL_MAX_SCALE);
buf->q_append(static_cast<char>(SESSION_TRACK_USER_VARIABLES));
ulonglong length= net_length_size(var->name.length) + var->name.length;
if (!null_value)
length+= net_length_size(value_str.length()) + value_str.length();
buf->q_net_store_length(length);
buf->q_net_store_data(reinterpret_cast<const uchar*>(var->name.str),
var->name.length);
if (!null_value)
buf->q_net_store_data(reinterpret_cast<const uchar*>(value_str.ptr()),
value_str.length());
}
m_changed_user_variables.clear();
return false;
}
///////////////////////////////////////////////////////////////////////////////
/**
......
......@@ -19,12 +19,14 @@
#include "m_string.h"
#include "thr_lock.h"
#include "sql_hset.h"
#ifndef EMBEDDED_LIBRARY
/* forward declarations */
class THD;
class set_var;
class String;
class user_var_entry;
enum enum_session_tracker
......@@ -33,6 +35,7 @@ enum enum_session_tracker
CURRENT_SCHEMA_TRACKER, /* Current schema */
SESSION_STATE_CHANGE_TRACKER,
TRANSACTION_INFO_TRACKER, /* Transaction state */
USER_VARIABLES_TRACKER,
SESSION_TRACKER_END /* must be the last */
};
......@@ -387,6 +390,35 @@ class Transaction_state_tracker : public State_tracker
thd->session_tracker.transaction_info.X; } while(0)
/**
User_variables_tracker
This is a tracker class that enables & manages the tracking of user variables.
*/
class User_variables_tracker: public State_tracker
{
Hash_set<const user_var_entry> m_changed_user_variables;
public:
User_variables_tracker():
m_changed_user_variables(&my_charset_bin, 0, 0,
sizeof(const user_var_entry*), 0, 0,
HASH_UNIQUE | (mysqld_server_initialized ?
HASH_THREAD_SPECIFIC : 0)) {}
bool update(THD *thd, set_var *var);
bool store(THD *thd, String *buf);
void mark_as_changed(THD *thd, const user_var_entry *var)
{
if (is_enabled())
{
m_changed_user_variables.insert(var);
set_changed(thd);
}
}
void deinit() { m_changed_user_variables.~Hash_set(); }
};
/**
Session_tracker
......@@ -415,6 +447,7 @@ class Session_tracker
Session_state_change_tracker state_change;
Transaction_state_tracker transaction_info;
Session_sysvars_tracker sysvars;
User_variables_tracker user_variables;
Session_tracker()
{
......@@ -422,6 +455,7 @@ class Session_tracker
m_trackers[CURRENT_SCHEMA_TRACKER]= &current_schema;
m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change;
m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info;
m_trackers[USER_VARIABLES_TRACKER]= &user_variables;
}
void enable(THD *thd)
......
......@@ -56,7 +56,6 @@
#include "rpl_filter.h"
#include "sql_table.h" // build_table_filename
#include "datadict.h" // dd_frm_is_view()
#include "sql_hset.h" // Hash_set
#include "rpl_rli.h" // rpl_group_info
#ifdef __WIN__
#include <io.h>
......
......@@ -1750,6 +1750,7 @@ THD::~THD()
/* trick to make happy memory accounting system */
#ifndef EMBEDDED_LIBRARY
session_tracker.sysvars.deinit();
session_tracker.user_variables.deinit();
#endif //EMBEDDED_LIBRARY
if (status_var.local_memory_used != 0)
......
......@@ -766,6 +766,7 @@ typedef struct system_variables
ulong session_track_transaction_info;
my_bool session_track_schema;
my_bool session_track_state_change;
my_bool session_track_user_variables;
my_bool tcp_nodelay;
ulong threadpool_priority;
......@@ -6319,7 +6320,7 @@ class user_var_entry
double val_real(bool *null_value);
longlong val_int(bool *null_value) const;
String *val_str(bool *null_value, String *str, uint decimals);
String *val_str(bool *null_value, String *str, uint decimals) const;
my_decimal *val_decimal(bool *null_value, my_decimal *result);
CHARSET_INFO *charset() const { return m_charset; }
void set_charset(CHARSET_INFO *cs) { m_charset= cs; }
......
......@@ -38,6 +38,13 @@ class Hash_set
m_hash.get_key= (my_hash_get_key)K;
m_hash.charset= cs;
}
Hash_set(CHARSET_INFO *charset, ulong default_array_elements,
size_t key_offset, size_t key_length, my_hash_get_key get_key,
void (*free_element)(void*), uint flags)
{
my_hash_init(&m_hash, charset, default_array_elements, key_offset,
key_length, get_key, free_element, flags);
}
/**
Destroy the hash by freeing the buckets table. Does
not call destructors for the elements.
......@@ -58,13 +65,8 @@ class Hash_set
bool insert(T *value)
{
my_hash_init_opt(&m_hash, m_hash.charset, START_SIZE, 0, 0,
m_hash.get_key, 0, MYF(0));
size_t key_len;
uchar *v= reinterpret_cast<uchar *>(value);
const uchar *key= m_hash.get_key(v, &key_len, FALSE);
if (find(key, key_len) == NULL)
return my_hash_insert(&m_hash, v);
return FALSE;
m_hash.get_key, 0, HASH_UNIQUE);
return my_hash_insert(&m_hash, reinterpret_cast<const uchar*>(value));
}
bool remove(T *value)
{
......@@ -78,6 +80,8 @@ class Hash_set
bool is_empty() const { return m_hash.records == 0; }
/** Returns the number of unique elements. */
size_t size() const { return static_cast<size_t>(m_hash.records); }
/** Erases all elements from the container */
void clear() { my_hash_reset(&m_hash); }
const T* at(size_t i) const
{
return reinterpret_cast<T*>(my_hash_element(const_cast<HASH*>(&m_hash), i));
......
......@@ -6378,6 +6378,22 @@ static Sys_var_mybool Sys_session_track_state_change(
ON_CHECK(0),
ON_UPDATE(update_session_track_state_change));
static bool update_session_track_user_variables(sys_var *self, THD *thd,
enum_var_type type)
{
return thd->session_tracker.user_variables.update(thd, 0);
}
static Sys_var_mybool Sys_session_track_user_variables(
"session_track_user_variables",
"Track changes to user variables.",
SESSION_VAR(session_track_user_variables),
CMD_LINE(OPT_ARG), DEFAULT(FALSE),
NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(0),
ON_UPDATE(update_session_track_user_variables));
#endif //EMBEDDED_LIBRARY
static Sys_var_uint Sys_in_subquery_conversion_threshold(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment