Commit c8948b0d authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-8931: (server part of) session state tracking

System variables tracking
parent e7608a78
......@@ -288,7 +288,7 @@ enum enum_server_command
CLIENT_MULTI_RESULTS | \
CLIENT_PS_MULTI_RESULTS | \
CLIENT_SSL_VERIFY_SERVER_CERT | \
CLIENT_REMEMBER_OPTIONS | \
CLIENT_REMEMBER_OPTIONS | \
MARIADB_CLIENT_PROGRESS | \
CLIENT_PLUGIN_AUTH | \
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
......@@ -556,9 +556,9 @@ enum enum_mysql_set_option
*/
enum enum_session_state_type
{
SESSION_TRACK_SYSTEM_VARIABLES, /* Session system variables */
SESSION_TRACK_SCHEMA, /* Current schema */
SESSION_TRACK_STATE_CHANGE, /* track session state changes */
SESSION_TRACK_SYSTEM_VARIABLES, /* Session system variables */
SESSION_TRACK_SCHEMA, /* Current schema */
SESSION_TRACK_STATE_CHANGE, /* track session state changes */
SESSION_TRACK_GTIDS,
SESSION_TRACK_TRANSACTION_CHARACTERISTICS, /* Transaction chistics */
SESSION_TRACK_TRANSACTION_STATE /* Transaction state */
......
......@@ -908,6 +908,8 @@ The following options may be given as the first argument:
(Defaults to on; use --skip-session-track-schema to disable.)
--session-track-state-change
Track changes to the 'session state'.
--session-track-system-variables=name
Track changes in registered system variables.
--show-slave-auth-info
Show user and password in SHOW SLAVE HOSTS on this
master.
......@@ -1392,6 +1394,7 @@ secure-file-priv (No default value)
server-id 1
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
show-slave-auth-info FALSE
silent-startup FALSE
skip-grant-tables TRUE
......
#
# Variable name : session_track_system_variables
# Scope : Global & Session
#
# Global - default
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
# Session - default
SELECT @@session.session_track_system_variables;
@@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;
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
# via INFORMATION_SCHEMA.SESSION_VARIABLES
SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track%' 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
SET @global_saved_tmp = @@global.session_track_system_variables;
# Altering global variable's value
SET @@global.session_track_system_variables='autocommit';
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
# Altering session variable's value
SET @@session.session_track_system_variables='autocommit';
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit
# Variables' values in a new session.
connect con1,"127.0.0.1",root,,test,$MASTER_MYPORT,;
# Global - expect "autocommit"
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit
# Session - expect "autocommit"
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit
# Switching to the default connection.
connection default;
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit
# Test if DEFAULT is working as expected.
SET @@global.session_track_system_variables = DEFAULT;
SET @@session.session_track_system_variables = DEFAULT;
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
# Variables' values in a new session (con2).
connect con2,"127.0.0.1",root,,test,$MASTER_MYPORT,;
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
# Altering session should not affect global.
SET @@session.session_track_system_variables = 'sql_mode';
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
sql_mode
# Variables' values in a new session (con3).
connect con3,"127.0.0.1",root,,test,$MASTER_MYPORT,;
# Altering global should not affect session.
SET @@global.session_track_system_variables = 'sql_mode';
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
sql_mode
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
# Switching to the default connection.
connection default;
# Testing NULL
SET @@global.session_track_system_variables = NULL;
SET @@session.session_track_system_variables = NULL;
# Global - expect "" instead of NULL
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
NULL
# Session - expect "" instead of NULL
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
# testing with duplicate entries.
SET @@global.session_track_system_variables= "time_zone";
SET @@session.session_track_system_variables= "time_zone";
SET @@global.session_track_system_variables= "sql_mode,sql_mode";
SET @@session.session_track_system_variables= "sql_mode,sql_mode";
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
sql_mode
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
sql_mode
# testing ordering
SET @@global.session_track_system_variables= "time_zone,sql_mode";
SET @@session.session_track_system_variables= "time_zone,sql_mode";
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
sql_mode,time_zone
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
sql_mode,time_zone
# special values
SET @@global.session_track_system_variables= "*";
SET @@session.session_track_system_variables= "*";
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
*
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
*
SET @@global.session_track_system_variables= "";
SET @@session.session_track_system_variables= "";
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
# Restoring the original values.
SET @@global.session_track_system_variables = @global_saved_tmp;
# End of tests.
......@@ -3817,6 +3817,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME SESSION_TRACK_SYSTEM_VARIABLES
SESSION_VALUE autocommit,character_set_client,character_set_connection,character_set_results,time_zone
GLOBAL_VALUE autocommit,character_set_client,character_set_connection,character_set_results,time_zone
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE autocommit,character_set_client,character_set_connection,character_set_results,time_zone
VARIABLE_SCOPE SESSION
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT Track changes in registered system variables.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME SKIP_EXTERNAL_LOCKING
SESSION_VALUE NULL
GLOBAL_VALUE ON
......
--source include/not_embedded.inc
--echo #
--echo # Variable name : session_track_system_variables
--echo # Scope : Global & Session
--echo #
--echo # Global - default
SELECT @@global.session_track_system_variables;
--echo # Session - default
SELECT @@session.session_track_system_variables;
--echo
--echo # via INFORMATION_SCHEMA.GLOBAL_VARIABLES
--disable_warnings
SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track%' ORDER BY VARIABLE_NAME;
--enable_warnings
--echo # via INFORMATION_SCHEMA.SESSION_VARIABLES
--disable_warnings
SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track%' ORDER BY VARIABLE_NAME;
--enable_warnings
# Save the global value to be used to restore the original value.
SET @global_saved_tmp = @@global.session_track_system_variables;
--echo
--echo # Altering global variable's value
SET @@global.session_track_system_variables='autocommit';
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # Altering session variable's value
SET @@session.session_track_system_variables='autocommit';
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # Variables' values in a new session.
connect (con1,"127.0.0.1",root,,test,$MASTER_MYPORT,);
--echo # Global - expect "autocommit"
SELECT @@global.session_track_system_variables;
--echo
--echo # Session - expect "autocommit"
SELECT @@session.session_track_system_variables;
--echo
--echo # Switching to the default connection.
connection default;
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # Test if DEFAULT is working as expected.
SET @@global.session_track_system_variables = DEFAULT;
SET @@session.session_track_system_variables = DEFAULT;
--echo
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # Variables' values in a new session (con2).
connect (con2,"127.0.0.1",root,,test,$MASTER_MYPORT,);
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # Altering session should not affect global.
SET @@session.session_track_system_variables = 'sql_mode';
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # Variables' values in a new session (con3).
connect (con3,"127.0.0.1",root,,test,$MASTER_MYPORT,);
--echo # Altering global should not affect session.
SET @@global.session_track_system_variables = 'sql_mode';
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # Switching to the default connection.
connection default;
--echo # Testing NULL
SET @@global.session_track_system_variables = NULL;
SET @@session.session_track_system_variables = NULL;
--echo # Global - expect "" instead of NULL
SELECT @@global.session_track_system_variables;
--echo # Session - expect "" instead of NULL
SELECT @@session.session_track_system_variables;
--echo # testing with duplicate entries.
# Lets first set it to some valid value.
SET @@global.session_track_system_variables= "time_zone";
SET @@session.session_track_system_variables= "time_zone";
# Now set with duplicate entries (must pass)
SET @@global.session_track_system_variables= "sql_mode,sql_mode";
SET @@session.session_track_system_variables= "sql_mode,sql_mode";
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # testing ordering
SET @@global.session_track_system_variables= "time_zone,sql_mode";
SET @@session.session_track_system_variables= "time_zone,sql_mode";
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # special values
SET @@global.session_track_system_variables= "*";
SET @@session.session_track_system_variables= "*";
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
SET @@global.session_track_system_variables= "";
SET @@session.session_track_system_variables= "";
SELECT @@global.session_track_system_variables;
SELECT @@session.session_track_system_variables;
--echo
--echo # Restoring the original values.
SET @@global.session_track_system_variables = @global_saved_tmp;
--echo # End of tests.
......@@ -690,6 +690,14 @@ THD *next_global_thread(THD *thd)
}
struct system_variables global_system_variables;
/**
Following is just for options parsing, used with a difference against
global_system_variables.
TODO: something should be done to get rid of following variables
*/
const char *current_dbug_option="";
struct system_variables max_system_variables;
struct system_status_var global_status_var;
......@@ -1463,7 +1471,6 @@ my_bool plugins_are_initialized= FALSE;
#ifndef DBUG_OFF
static const char* default_dbug_option;
#endif
const char *current_dbug_option="";
#ifdef HAVE_LIBWRAP
const char *libwrapName= NULL;
int allow_severity = LOG_INFO;
......@@ -5278,6 +5285,17 @@ static int init_server_components()
}
plugins_are_initialized= TRUE; /* Don't separate from init function */
{
Session_tracker session_track_system_variables_check;
if (session_track_system_variables_check.
server_boot_verify(system_charset_info))
{
sql_print_error("The variable session_track_system_variables has "
"invalid values.");
unireg_abort(1);
}
}
/* we do want to exit if there are any other unknown options */
if (remaining_argc > 1)
{
......
......@@ -135,6 +135,7 @@ extern my_bool lower_case_file_system;
extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
extern my_bool opt_secure_auth;
extern const char *current_dbug_option;
extern const char *current_session_track_system_variables;
extern char* opt_secure_file_priv;
extern char* opt_secure_backup_file_priv;
extern size_t opt_secure_backup_file_priv_len;
......
......@@ -276,7 +276,6 @@ net_send_ok(THD *thd,
/* the info field */
if (state_changed || (message && message[0]))
{
DBUG_ASSERT(strlen(message) <= MYSQL_ERRMSG_SIZE);
store.q_net_store_data((uchar*) message, message ? strlen(message) : 0);
}
......
This diff is collapsed.
......@@ -104,6 +104,12 @@ class State_tracker
virtual void mark_as_changed(THD *thd, LEX_CSTRING *name)= 0;
};
bool sysvartrack_validate_value(THD *thd, const char *str, size_t len);
bool sysvartrack_reprint_value(THD *thd, char *str, size_t len);
bool sysvartrack_update(THD *thd);
size_t sysvartrack_value_len(THD *thd);
bool sysvartrack_value_construct(THD *thd, char *val, size_t len);
/**
Session_tracker
......@@ -133,11 +139,23 @@ class Session_tracker
Session_tracker();
~Session_tracker()
{
deinit();
}
/* trick to make happy memory accounting system */
void deinit()
{
for (int i= 0; i <= SESSION_TRACKER_END; i ++)
delete m_trackers[i];
{
if (m_trackers[i])
delete m_trackers[i];
m_trackers[i]= NULL;
}
}
void enable(THD *thd);
bool server_boot_verify(const CHARSET_INFO *char_set);
/** Returns the pointer to the tracker object for the specified tracker. */
inline State_tracker *get_tracker(enum_session_tracker tracker) const
......
......@@ -115,6 +115,9 @@ void sys_var_end()
DBUG_VOID_RETURN;
}
static bool static_test_load= TRUE;
/**
sys_var constructor
......@@ -184,6 +187,8 @@ sys_var::sys_var(sys_var_chain *chain, const char *name_arg,
else
chain->first= this;
chain->last= this;
test_load= &static_test_load;
}
bool sys_var::update(THD *thd, set_var *var)
......@@ -215,13 +220,14 @@ bool sys_var::update(THD *thd, set_var *var)
*/
if ((var->type == OPT_SESSION) && (!ret))
{
thd->session_tracker.mark_as_changed(thd, SESSION_SYSVARS_TRACKER,
(LEX_CSTRING*)var->var);
/*
Here MySQL sends variable name to avoid reporting change of
the tracker itself, but we decided that it is not needed
*/
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
NULL);
}
return ret;
......@@ -995,7 +1001,30 @@ int set_var_collation_client::update(THD *thd)
thd->update_charset(character_set_client, collation_connection,
character_set_results);
/* Mark client collation variables as changed */
if (thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled())
{
sys_var *svar;
mysql_mutex_lock(&LOCK_plugin);
if ((svar= find_sys_var_ex(thd, "character_set_client",
sizeof("character_set_client") - 1,
false, true)))
thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->
mark_as_changed(thd, (LEX_CSTRING*)svar);
if ((svar= find_sys_var_ex(thd, "character_set_results",
sizeof("character_set_results") - 1,
false, true)))
thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->
mark_as_changed(thd, (LEX_CSTRING*)svar);
if ((svar= find_sys_var_ex(thd, "character_set_connection",
sizeof("character_set_connection") - 1,
false, true)))
thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->
mark_as_changed(thd, (LEX_CSTRING*)svar);
mysql_mutex_unlock(&LOCK_plugin);
}
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
thd->protocol_text.init(thd);
thd->protocol_binary.init(thd);
return 0;
......
......@@ -48,6 +48,9 @@ struct sys_var_chain
int mysql_add_sys_var_chain(sys_var *chain);
int mysql_del_sys_var_chain(sys_var *chain);
extern const LEX_CSTRING SESSION_TRACK_SYSTEM_VARIABLES_NAME;
/**
A class representing one system variable - that is something
that can be accessed as @@global.variable_name or @@session.variable_name,
......@@ -60,6 +63,7 @@ class sys_var: protected Value_source // for double_from_string_with_check
public:
sys_var *next;
LEX_CSTRING name;
bool *test_load;
enum flag_enum { GLOBAL, SESSION, ONLY_SESSION, SCOPE_MASK=1023,
READONLY=1024, ALLOCATED=2048, PARSE_EARLY=4096,
NO_SET_STATEMENT=8192, AUTO_SET=16384};
......@@ -240,6 +244,9 @@ class sys_var: protected Value_source // for double_from_string_with_check
uchar *global_var_ptr()
{ return ((uchar*)&global_system_variables) + offset; }
friend class Session_sysvars_tracker;
friend class Session_tracker;
};
#include "sql_plugin.h" /* SHOW_HA_ROWS, SHOW_MY_BOOL */
......
......@@ -4064,21 +4064,21 @@ ER_LOCK_OR_ACTIVE_TRANSACTION
swe "Kan inte utföra kommandot emedan du har en låst tabell eller an aktiv transaktion"
ukr "Не можу виконати подану команду тому, що таблиця заблокована або виконується транзакція"
ER_UNKNOWN_SYSTEM_VARIABLE
cze "Neznámá systémová proměnná '%-.64s'"
dan "Ukendt systemvariabel '%-.64s'"
nla "Onbekende systeem variabele '%-.64s'"
eng "Unknown system variable '%-.64s'"
est "Tundmatu süsteemne muutuja '%-.64s'"
fre "Variable système '%-.64s' inconnue"
ger "Unbekannte Systemvariable '%-.64s'"
ita "Variabile di sistema '%-.64s' sconosciuta"
jpn "'%-.64s' は不明なシステム変数です。"
por "Variável de sistema '%-.64s' desconhecida"
rus "Неизвестная системная переменная '%-.64s'"
serbian "Nepoznata sistemska promenljiva '%-.64s'"
spa "Desconocida variable de sistema '%-.64s'"
swe "Okänd systemvariabel: '%-.64s'"
ukr "Невідома системна змінна '%-.64s'"
cze "Neznámá systémová proměnná '%-.*s'"
dan "Ukendt systemvariabel '%-.*s'"
nla "Onbekende systeem variabele '%-.*s'"
eng "Unknown system variable '%-.*s'"
est "Tundmatu süsteemne muutuja '%-.*s'"
fre "Variable système '%-.*s' inconnue"
ger "Unbekannte Systemvariable '%-.*s'"
ita "Variabile di sistema '%-.*s' sconosciuta"
jpn "'%-.*s' は不明なシステム変数です。"
por "Variável de sistema '%-.*s' desconhecida"
rus "Неизвестная системная переменная '%-.*s'"
serbian "Nepoznata sistemska promenljiva '%-.*s'"
spa "Desconocida variable de sistema '%-.*s'"
swe "Okänd systemvariabel: '%-.*s'"
ukr "Невідома системна змінна '%-.*s'"
ER_CRASHED_ON_USAGE
cze "Tabulka '%-.192s' je označena jako porušená a měla by být opravena"
dan "Tabellen '%-.192s' er markeret med fejl og bør repareres"
......
......@@ -1766,6 +1766,10 @@ THD::~THD()
lf_hash_put_pins(xid_hash_pins);
/* Ensure everything is freed */
status_var.local_memory_used-= sizeof(THD);
/* trick to make happy memory accounting system */
session_tracker.deinit();
if (status_var.local_memory_used != 0)
{
DBUG_PRINT("error", ("memory_used: %lld", status_var.local_memory_used));
......
......@@ -691,6 +691,8 @@ typedef struct system_variables
my_bool session_track_schema;
my_bool session_track_state_change;
char *session_track_system_variables;
} SV;
/**
......
......@@ -269,6 +269,7 @@ struct st_bookmark
uint name_len;
int offset;
uint version;
bool loaded;
char key[1];
};
......@@ -322,6 +323,8 @@ static void unlock_variables(THD *thd, struct system_variables *vars);
static void cleanup_variables(struct system_variables *vars);
static void plugin_vars_free_values(sys_var *vars);
static void restore_ptr_backup(uint n, st_ptr_backup *backup);
#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B)
#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B)
static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin);
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
static void reap_plugins(void);
......@@ -1175,6 +1178,13 @@ static bool plugin_add(MEM_ROOT *tmp_root,
DBUG_RETURN(errs > 0 || oks + dupes == 0);
}
static void plugin_variables_deinit(struct st_plugin_int *plugin)
{
for (sys_var *var= plugin->system_vars; var; var= var->next)
(*var->test_load)= FALSE;
mysql_del_sys_var_chain(plugin->system_vars);
}
static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
{
......@@ -1226,8 +1236,7 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
if (ref_check && plugin->ref_count)
sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
plugin->name.str, plugin->ref_count);
mysql_del_sys_var_chain(plugin->system_vars);
plugin_variables_deinit(plugin);
}
static void plugin_del(struct st_plugin_int *plugin)
......@@ -1447,7 +1456,7 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin,
err:
if (ret)
mysql_del_sys_var_chain(plugin->system_vars);
plugin_variables_deinit(plugin);
mysql_mutex_lock(&LOCK_plugin);
plugin->state= state;
......@@ -2780,22 +2789,24 @@ static void update_func_double(THD *thd, struct st_mysql_sys_var *var,
System Variables support
****************************************************************************/
sys_var *find_sys_var(THD *thd, const char *str, size_t length)
sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length,
bool throw_error, bool locked)
{
sys_var *var;
sys_var_pluginvar *pi= NULL;
plugin_ref plugin;
DBUG_ENTER("find_sys_var");
DBUG_ENTER("find_sys_var_ex");
DBUG_PRINT("enter", ("var '%.*s'", (int)length, str));
mysql_mutex_lock(&LOCK_plugin);
if (!locked)
mysql_mutex_lock(&LOCK_plugin);
mysql_rwlock_rdlock(&LOCK_system_variables_hash);
if ((var= intern_find_sys_var(str, length)) &&
(pi= var->cast_pluginvar()))
{
mysql_rwlock_unlock(&LOCK_system_variables_hash);
LEX *lex= thd ? thd->lex : 0;
if (!(plugin= intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
if (!(plugin= my_intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
var= NULL; /* failed to lock it, it must be uninstalling */
else
if (!(plugin_state(plugin) & PLUGIN_IS_READY))
......@@ -2807,14 +2818,20 @@ sys_var *find_sys_var(THD *thd, const char *str, size_t length)
}
else
mysql_rwlock_unlock(&LOCK_system_variables_hash);
mysql_mutex_unlock(&LOCK_plugin);
if (!locked)
mysql_mutex_unlock(&LOCK_plugin);
if (!var)
my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
if (!throw_error && !var)
my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (int)length, (char*) str);
DBUG_RETURN(var);
}
sys_var *find_sys_var(THD *thd, const char *str, size_t length)
{
return find_sys_var_ex(thd, str, length, false, false);
}
/*
called by register_var, construct_options and test_plugin_options.
Returns the 'bookmark' for the named variable.
......@@ -3940,6 +3957,14 @@ my_bool mark_changed(int, const struct my_option *opt, char *)
return 0;
}
/**
It is always false to mark global plugin variable unloaded just to be
safe because we have no way now to know truth about them.
TODO: make correct mechanism for global plugin variables
*/
static bool static_unload= FALSE;
/**
Create and register system variables supplied from the plugin and
assigns initial values from corresponding command line arguments.
......@@ -4017,9 +4042,13 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
tmp_backup[tmp->nbackups++].save(&o->name);
if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
{
varname= var->key + 1;
var->loaded= TRUE;
}
else
{
var= NULL;
len= tmp->name.length + strlen(o->name) + 2;
varname= (char*) alloc_root(mem_root, len);
strxmov(varname, tmp->name.str, "-", o->name, NullS);
......@@ -4027,6 +4056,9 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
convert_dash_to_underscore(varname, len-1);
}
v= new (mem_root) sys_var_pluginvar(&chain, varname, tmp, o);
v->test_load= (var ? &var->loaded : &static_unload);
DBUG_ASSERT(static_unload == FALSE);
if (!(o->flags & PLUGIN_VAR_NOCMDOPT))
{
// update app_type, used for I_S.SYSTEM_VARIABLES
......
......@@ -192,4 +192,6 @@ extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
extern bool plugin_dl_foreach(THD *thd, const LEX_STRING *dl,
plugin_foreach_func *func, void *arg);
sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length,
bool throw_error, bool locked);
#endif
......@@ -3212,6 +3212,132 @@ void remove_status_vars(SHOW_VAR *list)
}
/**
@brief Returns the value of a system or a status variable.
@param thd [in] The handle of the current THD.
@param variable [in] Details of the variable.
@param value_type [in] Variable type.
@param show_type [in] Variable show type.
@param charset [out] Character set of the value.
@param buff [in,out] Buffer to store the value.
(Needs to have enough memory
to hold the value of variable.)
@param length [out] Length of the value.
@return Pointer to the value buffer.
*/
const char* get_one_variable(THD *thd,
const SHOW_VAR *variable,
enum_var_type value_type, SHOW_TYPE show_type,
system_status_var *status_var,
const CHARSET_INFO **charset, char *buff,
size_t *length)
{
void *value= variable->value;
const char *pos= buff;
const char *end= buff;
if (show_type == SHOW_SYS)
{
sys_var *var= (sys_var *) value;
show_type= var->show_type();
value= var->value_ptr(thd, value_type, &null_lex_str);
*charset= var->charset(thd);
}
/*
note that value may be == buff. All SHOW_xxx code below
should still work in this case
*/
switch (show_type) {
case SHOW_DOUBLE_STATUS:
value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_DOUBLE:
/* 6 is the default precision for '%f' in sprintf() */
end= buff + my_fcvt(*(double *) value, 6, buff, NULL);
break;
case SHOW_LONG_STATUS:
value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_ULONG:
case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
end= int10_to_str(*(long*) value, buff, 10);
break;
case SHOW_LONGLONG_STATUS:
value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_ULONGLONG:
end= longlong10_to_str(*(longlong*) value, buff, 10);
break;
case SHOW_HA_ROWS:
end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
break;
case SHOW_BOOL:
end= strmov(buff, *(bool*) value ? "ON" : "OFF");
break;
case SHOW_MY_BOOL:
end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
break;
case SHOW_UINT:
end= int10_to_str((long) *(uint*) value, buff, 10);
break;
case SHOW_SINT:
end= int10_to_str((long) *(int*) value, buff, -10);
break;
case SHOW_SLONG:
end= int10_to_str(*(long*) value, buff, -10);
break;
case SHOW_SLONGLONG:
end= longlong10_to_str(*(longlong*) value, buff, -10);
break;
case SHOW_HAVE:
{
SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
pos= show_comp_option_name[(int) tmp];
end= strend(pos);
break;
}
case SHOW_CHAR:
{
if (!(pos= (char*)value))
pos= "";
end= strend(pos);
break;
}
case SHOW_CHAR_PTR:
{
if (!(pos= *(char**) value))
pos= "";
end= strend(pos);
break;
}
case SHOW_LEX_STRING:
{
LEX_STRING *ls=(LEX_STRING*)value;
if (!(pos= ls->str))
end= pos= "";
else
end= pos + ls->length;
break;
}
case SHOW_UNDEF:
break; // Return empty string
case SHOW_SYS: // Cannot happen
default:
DBUG_ASSERT(0);
break;
}
*length= (size_t) (end - pos);
return pos;
}
static bool show_status_array(THD *thd, const char *wild,
SHOW_VAR *variables,
enum enum_var_type scope,
......@@ -3324,109 +3450,21 @@ static bool show_status_array(THD *thd, const char *wild,
name_buffer, wild))) &&
(!cond || cond->val_int()))
{
void *value=var->value;
const char *pos, *end; // We assign a lot of const's
const char *pos; // We assign a lot of const's
size_t length;
if (show_type == SHOW_SYS)
{
sys_var *var= (sys_var *) value;
show_type= var->show_type();
mysql_mutex_lock(&LOCK_global_system_variables);
value= var->value_ptr(thd, scope, &null_lex_str);
charset= var->charset(thd);
}
pos= get_one_variable(thd, var, scope, show_type, status_var,
&charset, buff, &length);
pos= end= buff;
/*
note that value may be == buff. All SHOW_xxx code below
should still work in this case
*/
switch (show_type) {
case SHOW_DOUBLE_STATUS:
value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_DOUBLE:
/* 6 is the default precision for '%f' in sprintf() */
end= buff + my_fcvt(*(double *) value, 6, buff, NULL);
break;
case SHOW_LONG_STATUS:
value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_ULONG:
case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
end= int10_to_str(*(long*) value, buff, 10);
break;
case SHOW_LONGLONG_STATUS:
value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_ULONGLONG:
end= longlong10_to_str(*(longlong*) value, buff, 10);
break;
case SHOW_HA_ROWS:
end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
break;
case SHOW_BOOL:
end= strmov(buff, *(bool*) value ? "ON" : "OFF");
break;
case SHOW_MY_BOOL:
end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
break;
case SHOW_UINT:
end= int10_to_str((long) *(uint*) value, buff, 10);
break;
case SHOW_SINT:
end= int10_to_str((long) *(int*) value, buff, -10);
break;
case SHOW_SLONG:
end= int10_to_str(*(long*) value, buff, -10);
break;
case SHOW_SLONGLONG:
end= longlong10_to_str(*(longlong*) value, buff, -10);
break;
case SHOW_HAVE:
{
SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
pos= show_comp_option_name[(int) tmp];
end= strend(pos);
break;
}
case SHOW_CHAR:
{
if (!(pos= (char*)value))
pos= "";
end= strend(pos);
break;
}
case SHOW_CHAR_PTR:
{
if (!(pos= *(char**) value))
pos= "";
end= strend(pos);
break;
}
case SHOW_LEX_STRING:
{
LEX_STRING *ls=(LEX_STRING*)value;
if (!(pos= ls->str))
end= pos= "";
else
end= pos + ls->length;
break;
}
case SHOW_UNDEF:
break; // Return empty string
case SHOW_SYS: // Cannot happen
default:
DBUG_ASSERT(0);
break;
}
table->field[1]->store(pos, (uint32) (end - pos), charset);
table->field[1]->store(pos, (uint32) length, charset);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
table->field[1]->set_notnull();
if (var->type == SHOW_SYS)
if (show_type == SHOW_SYS)
mysql_mutex_unlock(&LOCK_global_system_variables);
if (schema_table_store_record(thd, table))
{
res= TRUE;
......
......@@ -131,6 +131,12 @@ bool get_schema_tables_result(JOIN *join,
enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list);
const char* get_one_variable(THD *thd, const SHOW_VAR *variable,
enum_var_type value_type, SHOW_TYPE show_type,
system_status_var *status_var,
const CHARSET_INFO **charset, char *buff,
size_t *length);
/* These functions were under INNODB_COMPATIBILITY_HOOKS */
int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
THD *find_thread_by_id(longlong id, bool query_id= false);
......
......@@ -359,7 +359,9 @@ class String
if (ALIGN_SIZE(arg_length+1) < Alloced_length)
{
char *new_ptr;
if (!(new_ptr=(char*) my_realloc(Ptr,arg_length,MYF(0))))
if (!(new_ptr=(char*)
my_realloc(Ptr, arg_length,MYF((thread_specific ?
MY_THREAD_SPECIFIC : 0)))))
{
Alloced_length = 0;
real_alloc(arg_length);
......
......@@ -5375,6 +5375,16 @@ static Sys_var_ulong Sys_log_tc_size(
BLOCK_SIZE(my_getpagesize()));
#endif
const LEX_CSTRING SESSION_TRACK_SYSTEM_VARIABLES_NAME=
{STRING_WITH_LEN("session_track_system_variables")};
static Sys_var_sesvartrack Sys_track_session_sys_vars(
SESSION_TRACK_SYSTEM_VARIABLES_NAME.str,
"Track changes in registered system variables.",
CMD_LINE(REQUIRED_ARG), IN_SYSTEM_CHARSET,
DEFAULT("autocommit,character_set_client,character_set_connection,"
"character_set_results,time_zone"),
NO_MUTEX_GUARD);
static bool update_session_track_schema(sys_var *self, THD *thd,
enum_var_type type)
......
......@@ -438,10 +438,10 @@ public:
does not destroy individual members of SV, there's no way to free
allocated string variables for every thread.
*/
class Sys_var_charptr: public sys_var
class Sys_var_charptr_base: public sys_var
{
public:
Sys_var_charptr(const char *name_arg,
Sys_var_charptr_base(const char *name_arg,
const char *comment, int flag_args, ptrdiff_t off, size_t size,
CMD_LINE getopt,
enum charset_enum is_os_charset_arg,
......@@ -463,8 +463,6 @@ public:
*/
option.var_type|= (flags & ALLOCATED) ? GET_STR_ALLOC : GET_STR;
global_var(const char*)= def_val;
SYSVAR_ASSERT(scope() == GLOBAL);
SYSVAR_ASSERT(size == sizeof(char *));
}
void cleanup()
{
......@@ -503,31 +501,35 @@ public:
}
bool do_check(THD *thd, set_var *var)
{ return do_string_check(thd, var, charset(thd)); }
bool session_update(THD *thd, set_var *var)
{
DBUG_ASSERT(FALSE);
return true;
}
bool global_update(THD *thd, set_var *var)
bool session_update(THD *thd, set_var *var)= 0;
char *global_update_prepare(THD *thd, set_var *var)
{
char *new_val, *ptr= var->save_result.string_value.str;
size_t len=var->save_result.string_value.length;
if (ptr)
{
new_val= (char*)my_memdup(ptr, len+1, MYF(MY_WME));
if (!new_val) return true;
if (!new_val) return 0;
new_val[len]=0;
}
else
new_val= 0;
return new_val;
}
void global_update_finish(char *new_val)
{
if (flags & ALLOCATED)
my_free(global_var(char*));
flags|= ALLOCATED;
global_var(char*)= new_val;
return false;
}
void session_save_default(THD *thd, set_var *var)
{ DBUG_ASSERT(FALSE); }
bool global_update(THD *thd, set_var *var)
{
char *new_val= global_update_prepare(thd, var);
global_update_finish(new_val);
return (new_val == 0 && var->save_result.string_value.str != 0);
}
void session_save_default(THD *thd, set_var *var)= 0;
void global_save_default(THD *thd, set_var *var)
{
char *ptr= (char*)(intptr)option.def_value;
......@@ -536,6 +538,105 @@ public:
}
};
class Sys_var_charptr: public Sys_var_charptr_base
{
public:
Sys_var_charptr(const char *name_arg,
const char *comment, int flag_args, ptrdiff_t off, size_t size,
CMD_LINE getopt,
enum charset_enum is_os_charset_arg,
const char *def_val, PolyLock *lock=0,
enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
on_check_function on_check_func=0,
on_update_function on_update_func=0,
const char *substitute=0) :
Sys_var_charptr_base(name_arg, comment, flag_args, off, size, getopt,
is_os_charset_arg, def_val, lock, binlog_status_arg,
on_check_func, on_update_func, substitute)
{
SYSVAR_ASSERT(scope() == GLOBAL);
SYSVAR_ASSERT(size == sizeof(char *));
}
bool session_update(THD *thd, set_var *var)
{
DBUG_ASSERT(FALSE);
return true;
}
void session_save_default(THD *thd, set_var *var)
{ DBUG_ASSERT(FALSE); }
};
class Sys_var_sesvartrack: public Sys_var_charptr_base
{
public:
Sys_var_sesvartrack(const char *name_arg,
const char *comment,
CMD_LINE getopt,
enum charset_enum is_os_charset_arg,
const char *def_val, PolyLock *lock) :
Sys_var_charptr_base(name_arg, comment,
SESSION_VAR(session_track_system_variables),
getopt, is_os_charset_arg, def_val, lock,
VARIABLE_NOT_IN_BINLOG, 0, 0, 0)
{}
bool do_check(THD *thd, set_var *var)
{
if (Sys_var_charptr_base::do_check(thd, var) ||
sysvartrack_validate_value(thd, var->save_result.string_value.str,
var->save_result.string_value.length))
return TRUE;
return FALSE;
}
bool global_update(THD *thd, set_var *var)
{
char *new_val= global_update_prepare(thd, var);
if (new_val)
{
if (sysvartrack_reprint_value(thd, new_val,
var->save_result.string_value.length))
new_val= 0;
}
global_update_finish(new_val);
return (new_val == 0 && var->save_result.string_value.str != 0);
}
bool session_update(THD *thd, set_var *var)
{
return sysvartrack_update(thd);
}
void session_save_default(THD *thd, set_var *var)
{
var->save_result.string_value.str= global_var(char*);
var->save_result.string_value.length=
strlen(var->save_result.string_value.str);
/* parse and feel list with default values */
if (thd)
{
bool res=
sysvartrack_validate_value(thd,
var->save_result.string_value.str,
var->save_result.string_value.length);
DBUG_ASSERT(res == 0);
}
}
uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
{
DBUG_ASSERT(thd != NULL);
size_t len= sysvartrack_value_len(thd);
char *res= 0;
char *buf= (char *)my_safe_alloca(len);
if (buf && !sysvartrack_value_construct(thd, buf, len))
{
size_t len= strlen(buf) + 1;
res= (char*) thd->alloc(len + sizeof(char *));
if (res)
memcpy((*((char**) res)= res + sizeof(char *)), buf, len);
my_safe_afree(buf, len);
}
return (uchar *)res;
}
};
class Sys_var_proxy_user: public sys_var
{
......
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