summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Vojtovich <svoj@mariadb.org>2019-06-20 18:02:40 +0400
committerSergey Vojtovich <svoj@mariadb.org>2019-09-23 15:37:51 +0400
commit6ba5174b5b52bf6fa55f054278967db25f8cf6a9 (patch)
treeb6cd0e25099ceafd6277cb568a87d6b7ddede1ca
parent36355060900611312c894d6726996cdd374a9554 (diff)
downloadmariadb-git-bb-10.5-svoj-MDEV-16470.tar.gz
MDEV-16470 - Session user variables trackerbb-10.5-svoj-MDEV-16470
Based on contribution by Dapeng Huang.
-rw-r--r--include/mysql.h.pp1
-rw-r--r--include/mysql_com.h1
-rw-r--r--mysql-test/main/mysqld--help.result3
-rw-r--r--mysql-test/main/mysqltest_tracking_info.result10
-rw-r--r--mysql-test/main/mysqltest_tracking_info.test11
-rw-r--r--mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result10
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result10
-rw-r--r--mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test4
-rw-r--r--sql/item_func.cc6
-rw-r--r--sql/session_tracker.cc33
-rw-r--r--sql/session_tracker.h34
-rw-r--r--sql/sql_base.cc1
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h3
-rw-r--r--sql/sql_hset.h18
-rw-r--r--sql/sys_vars.cc16
16 files changed, 141 insertions, 21 deletions
diff --git a/include/mysql.h.pp b/include/mysql.h.pp
index ed47b32d37a..4fcfab4aea4 100644
--- a/include/mysql.h.pp
+++ b/include/mysql.h.pp
@@ -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" {
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 8b1f09e4703..4eafe148743 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -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 */
};
diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result
index de43900ed76..9d3f4198261 100644
--- a/mysql-test/main/mysqld--help.result
+++ b/mysql-test/main/mysqld--help.result
@@ -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
diff --git a/mysql-test/main/mysqltest_tracking_info.result b/mysql-test/main/mysqltest_tracking_info.result
index df966ae1d39..d2eaa5afea8 100644
--- a/mysql-test/main/mysqltest_tracking_info.result
+++ b/mysql-test/main/mysqltest_tracking_info.result
@@ -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;
diff --git a/mysql-test/main/mysqltest_tracking_info.test b/mysql-test/main/mysqltest_tracking_info.test
index d31f68b3cbd..405b920051a 100644
--- a/mysql-test/main/mysqltest_tracking_info.test
+++ b/mysql-test/main/mysqltest_tracking_info.test
@@ -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;
diff --git a/mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result b/mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result
index 78ca8ca4ad1..bb34436b4ec 100644
--- a/mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result
+++ b/mysql-test/suite/sys_vars/r/session_track_system_variables_basic.result
@@ -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
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index 3e50dcb942f..cb4496ca9d7 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -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
diff --git a/mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test b/mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test
index 90e6052947c..e58d405cf0a 100644
--- a/mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test
+++ b/mysql-test/suite/sys_vars/t/session_track_system_variables_basic.test
@@ -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;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 10ac0f74644..2eb7250ebc7 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -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;
diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc
index fe5cd3a5d61..dc22d6dc9a3 100644
--- a/sql/session_tracker.cc
+++ b/sql/session_tracker.cc
@@ -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;
+}
+
///////////////////////////////////////////////////////////////////////////////
/**
diff --git a/sql/session_tracker.h b/sql/session_tracker.h
index 269b1bd2359..b91e588a34e 100644
--- a/sql/session_tracker.h
+++ b/sql/session_tracker.h
@@ -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 */
};
@@ -388,6 +391,35 @@ private:
/**
+ 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
This class holds an object each for all tracker classes and provides
@@ -415,6 +447,7 @@ public:
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 @@ public:
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)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 54491c2362b..aa13f8a24db 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -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>
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 91fc482978d..93f1ae7c1eb 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -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)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a3d4b4e87d4..f6434605a74 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -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; }
diff --git a/sql/sql_hset.h b/sql/sql_hset.h
index 7834349a2f7..aaecef9f0d4 100644
--- a/sql/sql_hset.h
+++ b/sql/sql_hset.h
@@ -38,6 +38,13 @@ public:
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 @@ public:
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 @@ public:
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));
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 1ba58bf71c4..1adc20af657 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -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(