summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2019-05-05 15:03:48 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2019-05-05 15:06:44 +0300
commitd3dcec5d657b83ca08b32f5a64b5dff01edfb13e (patch)
tree5fd801aa0daf5e74689b17ed50a086a8acd7d6e7 /sql
parentb132b8895e2e59df457e063451f186b53576b034 (diff)
parente8dd18a474ee6b48eb7f92e3831f9e359b0bdc6e (diff)
downloadmariadb-git-d3dcec5d657b83ca08b32f5a64b5dff01edfb13e.tar.gz
Merge 10.3 into 10.4
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc11
-rw-r--r--sql/item.h7
-rw-r--r--sql/item_sum.cc14
-rw-r--r--sql/lock.cc11
-rw-r--r--sql/log.cc2
-rw-r--r--sql/mysqld.cc17
-rw-r--r--sql/semisync_master.cc11
-rw-r--r--sql/semisync_master.h8
-rw-r--r--sql/semisync_master_ack_receiver.cc3
-rw-r--r--sql/session_tracker.cc765
-rw-r--r--sql/session_tracker.h287
-rw-r--r--sql/set_var.cc8
-rw-r--r--sql/set_var.h3
-rw-r--r--sql/signal_handler.cc46
-rw-r--r--sql/sql_acl.cc4
-rw-r--r--sql/sql_analyze_stmt.cc10
-rw-r--r--sql/sql_class.cc22
-rw-r--r--sql/sql_class.h11
-rw-r--r--sql/sql_lex.cc5
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_plugin.cc47
-rw-r--r--sql/sql_plugin.h3
-rw-r--r--sql/sql_show.cc17
-rw-r--r--sql/sql_trigger.h2
-rw-r--r--sql/sql_type.cc2
-rw-r--r--sql/sql_union.cc40
-rw-r--r--sql/sys_vars.cc27
-rw-r--r--sql/sys_vars.ic37
-rw-r--r--sql/table.cc20
-rw-r--r--sql/transaction.cc37
-rw-r--r--sql/wsrep_server_service.cc8
31 files changed, 614 insertions, 872 deletions
diff --git a/sql/item.cc b/sql/item.cc
index e511921b30b..72231497a22 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2018, Oracle and/or its affiliates.
- Copyright (c) 2010, 2018, MariaDB Corporation
+ Copyright (c) 2010, 2019, MariaDB Corporation
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
@@ -265,6 +265,15 @@ longlong Item::val_int_unsigned_typecast_from_str()
}
+longlong Item::val_int_signed_typecast_from_int()
+{
+ longlong value= val_int();
+ if (!null_value && unsigned_flag && value < 0)
+ push_note_converted_to_negative_complement(current_thd);
+ return value;
+}
+
+
longlong Item::val_int_unsigned_typecast_from_int()
{
longlong value= val_int();
diff --git a/sql/item.h b/sql/item.h
index b2f66b5292c..ec474b81a08 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1247,6 +1247,13 @@ public:
}
longlong val_int_unsigned_typecast_from_int();
longlong val_int_unsigned_typecast_from_str();
+
+ /**
+ Get a value for CAST(x AS UNSIGNED).
+ Huge positive unsigned values are converted to negative complements.
+ */
+ longlong val_int_signed_typecast_from_int();
+
/*
This is just a shortcut to avoid the cast. You should still use
unsigned_flag to check the sign of the item.
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index e4063f9ef83..e1c8af98dd7 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -4134,7 +4134,19 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
}
str->append(STRING_WITH_LEN(" separator \'"));
str->append_for_single_quote(separator->ptr(), separator->length());
- str->append(STRING_WITH_LEN("\')"));
+ str->append(STRING_WITH_LEN("\'"));
+
+ if (limit_clause)
+ {
+ str->append(STRING_WITH_LEN(" limit "));
+ if (offset_limit)
+ {
+ offset_limit->print(str, query_type);
+ str->append(',');
+ }
+ row_limit->print(str, query_type);
+ }
+ str->append(STRING_WITH_LEN(")"));
}
diff --git a/sql/lock.cc b/sql/lock.cc
index fe745b49003..d53aad5a2ba 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -253,16 +253,11 @@ static void track_table_access(THD *thd, TABLE **tables, size_t count)
{
if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
{
- Transaction_state_tracker *tst= (Transaction_state_tracker *)
- thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER);
-
while (count--)
{
- TABLE *t= tables[count];
-
- if (t)
- tst->add_trx_state(thd, t->reginfo.lock_type,
- t->file->has_transaction_manager());
+ if (TABLE *t= tables[count])
+ thd->session_tracker.transaction_info.add_trx_state(thd,
+ t->reginfo.lock_type, t->file->has_transaction_manager());
}
}
}
diff --git a/sql/log.cc b/sql/log.cc
index 9f724534e6e..aa63736b796 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -7964,6 +7964,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
*/
for (current= queue; current != NULL; current= current->next)
{
+ set_current_thd(current->thd);
binlog_cache_mngr *cache_mngr= current->cache_mngr;
/*
@@ -7999,6 +8000,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
cache_mngr->delayed_error= false;
}
}
+ set_current_thd(leader->thd);
bool synced= 0;
if (unlikely(flush_and_sync(&synced)))
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index bfa03aa57c1..dbe6055d387 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -889,6 +889,7 @@ PSI_mutex_key key_LOCK_relaylog_end_pos;
PSI_mutex_key key_LOCK_thread_id;
PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state,
key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry;
+PSI_mutex_key key_LOCK_rpl_semi_sync_master_enabled;
PSI_mutex_key key_LOCK_binlog;
PSI_mutex_key key_LOCK_stats,
@@ -983,6 +984,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_rpl_thread_pool, "LOCK_rpl_thread_pool", 0},
{ &key_LOCK_parallel_entry, "LOCK_parallel_entry", 0},
{ &key_LOCK_ack_receiver, "Ack_receiver::mutex", 0},
+ { &key_LOCK_rpl_semi_sync_master_enabled, "LOCK_rpl_semi_sync_master_enabled", 0},
{ &key_LOCK_binlog, "LOCK_binlog", 0}
};
@@ -2724,9 +2726,8 @@ static bool cache_thread(THD *thd)
Create new instrumentation for the new THD job,
and attach it to this running pthread.
*/
- PSI_thread *psi= PSI_CALL_new_thread(key_thread_one_connection,
- thd, thd->thread_id);
- PSI_CALL_set_thread(psi);
+ PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection,
+ thd, thd->thread_id));
/* reset abort flag for the thread */
thd->mysys_var->abort= 0;
@@ -5194,14 +5195,8 @@ static int init_server_components()
#endif
#ifndef EMBEDDED_LIBRARY
- {
- if (Session_tracker::server_boot_verify(system_charset_info))
- {
- sql_print_error("The variable session_track_system_variables has "
- "invalid values.");
- unireg_abort(1);
- }
- }
+ if (session_tracker_init())
+ return 1;
#endif //EMBEDDED_LIBRARY
/* we do want to exit if there are any other unknown options */
diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc
index 4e37e3af58d..f9fb4d9147d 100644
--- a/sql/semisync_master.cc
+++ b/sql/semisync_master.cc
@@ -352,7 +352,7 @@ Repl_semi_sync_master::Repl_semi_sync_master()
int Repl_semi_sync_master::init_object()
{
- int result;
+ int result= 0;
m_init_done = true;
@@ -362,6 +362,8 @@ int Repl_semi_sync_master::init_object()
set_wait_point(rpl_semi_sync_master_wait_point);
/* Mutex initialization can only be done after MY_INIT(). */
+ mysql_mutex_init(key_LOCK_rpl_semi_sync_master_enabled,
+ &LOCK_rpl_semi_sync_master_enabled, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_binlog,
&LOCK_binlog, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_binlog_send,
@@ -383,7 +385,7 @@ int Repl_semi_sync_master::init_object()
}
else
{
- result = disable_master();
+ disable_master();
}
return result;
@@ -421,7 +423,7 @@ int Repl_semi_sync_master::enable_master()
return result;
}
-int Repl_semi_sync_master::disable_master()
+void Repl_semi_sync_master::disable_master()
{
/* Must have the lock when we do enable of disable. */
lock();
@@ -446,14 +448,13 @@ int Repl_semi_sync_master::disable_master()
}
unlock();
-
- return 0;
}
void Repl_semi_sync_master::cleanup()
{
if (m_init_done)
{
+ mysql_mutex_destroy(&LOCK_rpl_semi_sync_master_enabled);
mysql_mutex_destroy(&LOCK_binlog);
mysql_cond_destroy(&COND_binlog_send);
m_init_done= 0;
diff --git a/sql/semisync_master.h b/sql/semisync_master.h
index de5e3240802..517175b5b06 100644
--- a/sql/semisync_master.h
+++ b/sql/semisync_master.h
@@ -23,6 +23,7 @@
#include "semisync_master_ack_receiver.h"
#ifdef HAVE_PSI_INTERFACE
+extern PSI_mutex_key key_LOCK_rpl_semi_sync_master_enabled;
extern PSI_mutex_key key_LOCK_binlog;
extern PSI_cond_key key_COND_binlog_send;
#endif
@@ -365,7 +366,6 @@ public:
*/
class Repl_semi_sync_master
:public Repl_semi_sync_base {
- private:
Active_tranx *m_active_tranxs; /* active transaction list: the list will
be cleared when semi-sync switches off. */
@@ -491,8 +491,8 @@ class Repl_semi_sync_master
/* Enable the object to enable semi-sync replication inside the master. */
int enable_master();
- /* Enable the object to enable semi-sync replication inside the master. */
- int disable_master();
+ /* Disable the object to disable semi-sync replication inside the master. */
+ void disable_master();
/* Add a semi-sync replication slave */
void add_slave();
@@ -619,6 +619,8 @@ class Repl_semi_sync_master
int before_reset_master();
void check_and_switch();
+
+ mysql_mutex_t LOCK_rpl_semi_sync_master_enabled;
};
enum rpl_semi_sync_master_wait_point_t {
diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc
index 0ef0b5229ca..e189fc5f631 100644
--- a/sql/semisync_master_ack_receiver.cc
+++ b/sql/semisync_master_ack_receiver.cc
@@ -185,8 +185,7 @@ static void init_net(NET *net, unsigned char *buff, unsigned int buff_len)
void Ack_receiver::run()
{
- // skip LOCK_global_system_variables due to the 3rd arg
- THD *thd= new THD(next_thread_id(), false, true);
+ THD *thd= new THD(next_thread_id());
NET net;
unsigned char net_buff[REPLY_MESSAGE_MAX_LENGTH];
diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc
index 0088f1b20de..1566c2d7ade 100644
--- a/sql/session_tracker.cc
+++ b/sql/session_tracker.cc
@@ -15,10 +15,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#ifndef EMBEDDED_LIBRARY
#include "sql_plugin.h"
-#include "session_tracker.h"
-
#include "hash.h"
#include "table.h"
#include "rpl_gtid.h"
@@ -35,264 +32,12 @@ void State_tracker::mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name)
}
-class Not_implemented_tracker : public State_tracker
-{
-public:
- bool enable(THD *thd)
- { return false; }
- bool update(THD *, set_var *)
- { return false; }
- bool store(THD *, String *)
- { return false; }
- void mark_as_changed(THD *, LEX_CSTRING *tracked_item_name)
- {}
-
-};
-
-/**
- Session_sysvars_tracker
-
- This is a tracker class that enables & manages the tracking of session
- system variables. It internally maintains a hash of user supplied variable
- references and a boolean field to store if the variable was changed by the
- last statement.
-*/
-
-class Session_sysvars_tracker : public State_tracker
-{
-private:
-
- struct sysvar_node_st {
- sys_var *m_svar;
- bool *test_load;
- bool m_changed;
- };
-
- class vars_list
- {
- private:
- /**
- Registered system variables. (@@session_track_system_variables)
- A hash to store the name of all the system variables specified by the
- user.
- */
- HASH m_registered_sysvars;
- /** Size of buffer for string representation */
- size_t buffer_length;
- myf m_mem_flag;
- /**
- If TRUE then we want to check all session variable.
- */
- bool track_all;
- void init()
- {
- my_hash_init(&m_registered_sysvars,
- &my_charset_bin,
- 4, 0, 0, (my_hash_get_key) sysvars_get_key,
- my_free, MYF(HASH_UNIQUE |
- ((m_mem_flag & MY_THREAD_SPECIFIC) ?
- HASH_THREAD_SPECIFIC : 0)));
- }
- void free_hash()
- {
- if (my_hash_inited(&m_registered_sysvars))
- {
- my_hash_free(&m_registered_sysvars);
- }
- }
-
- uchar* search(const sys_var *svar)
- {
- return (my_hash_search(&m_registered_sysvars, (const uchar *)&svar,
- sizeof(sys_var *)));
- }
-
- public:
- vars_list() :
- buffer_length(0)
- {
- m_mem_flag= current_thd ? MY_THREAD_SPECIFIC : 0;
- init();
- }
-
- size_t get_buffer_length()
- {
- DBUG_ASSERT(buffer_length != 0); // asked earlier then should
- return buffer_length;
- }
- ~vars_list()
- {
- /* free the allocated hash. */
- if (my_hash_inited(&m_registered_sysvars))
- {
- my_hash_free(&m_registered_sysvars);
- }
- }
-
- uchar* insert_or_search(sysvar_node_st *node, const sys_var *svar)
- {
- uchar *res;
- res= search(svar);
- if (!res)
- {
- if (track_all)
- {
- insert(node, svar, m_mem_flag);
- return search(svar);
- }
- }
- return res;
- }
-
- bool insert(sysvar_node_st *node, const sys_var *svar, myf mem_flag);
- void reinit();
- void reset();
- inline bool is_enabled()
- {
- return track_all || m_registered_sysvars.records;
- }
- void copy(vars_list* from, THD *thd);
- bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error,
- CHARSET_INFO *char_set, bool take_mutex);
- bool construct_var_list(char *buf, size_t buf_len);
- bool store(THD *thd, String *buf);
- };
- /**
- Two objects of vars_list type are maintained to manage
- various operations.
- */
- vars_list *orig_list, *tool_list;
-
-public:
- Session_sysvars_tracker()
- {
- orig_list= new (std::nothrow) vars_list();
- tool_list= new (std::nothrow) vars_list();
- }
-
- ~Session_sysvars_tracker()
- {
- if (orig_list)
- delete orig_list;
- if (tool_list)
- delete tool_list;
- }
-
- size_t get_buffer_length()
- {
- return orig_list->get_buffer_length();
- }
- bool construct_var_list(char *buf, size_t buf_len)
- {
- return orig_list->construct_var_list(buf, buf_len);
- }
-
- /**
- Method used to check the validity of string provided
- for session_track_system_variables during the server
- startup.
- */
- static bool server_init_check(THD *thd, CHARSET_INFO *char_set,
- LEX_STRING var_list)
- {
- return check_var_list(thd, var_list, false, char_set, false);
- }
-
- static bool server_init_process(THD *thd, CHARSET_INFO *char_set,
- LEX_STRING var_list)
- {
- vars_list dummy;
- bool result;
- result= dummy.parse_var_list(thd, var_list, false, char_set, false);
- if (!result)
- dummy.construct_var_list(var_list.str, var_list.length + 1);
- return result;
- }
-
- void reset();
- bool enable(THD *thd);
- bool check_str(THD *thd, LEX_STRING *val);
- bool update(THD *thd, set_var *var);
- bool store(THD *thd, String *buf);
- void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name);
- /* callback */
- static uchar *sysvars_get_key(const char *entry, size_t *length,
- my_bool not_used __attribute__((unused)));
-
- // hash iterators
- static my_bool name_array_filler(void *ptr, void *data_ptr);
- static my_bool store_variable(void *ptr, void *data_ptr);
- static my_bool reset_variable(void *ptr, void *data_ptr);
-
- static bool check_var_list(THD *thd, LEX_STRING var_list, bool throw_error,
- CHARSET_INFO *char_set, bool take_mutex);
-};
-
-
-
-/**
- Current_schema_tracker,
-
- This is a tracker class that enables & manages the tracking of current
- schema for a particular connection.
-*/
-
-class Current_schema_tracker : public State_tracker
-{
-private:
- bool schema_track_inited;
- void reset();
-
-public:
-
- Current_schema_tracker()
- {
- schema_track_inited= false;
- }
-
- bool enable(THD *thd)
- { return update(thd, NULL); }
- bool update(THD *thd, set_var *var);
- bool store(THD *thd, String *buf);
-};
-
-/*
- Session_state_change_tracker
-
- This is a boolean tracker class that will monitor any change that contributes
- to a session state change.
- Attributes that contribute to session state change include:
- - Successful change to System variables
- - User defined variables assignments
- - temporary tables created, altered or deleted
- - prepared statements added or removed
- - change in current database
- - change of current role
-*/
-
-class Session_state_change_tracker : public State_tracker
-{
-private:
-
- void reset();
-
-public:
- Session_state_change_tracker();
- bool enable(THD *thd)
- { return update(thd, NULL); };
- bool update(THD *thd, set_var *var);
- bool store(THD *thd, String *buf);
- bool is_state_changed(THD*);
-};
-
-
/* To be used in expanding the buffer. */
static const unsigned int EXTRA_ALLOC= 1024;
void Session_sysvars_tracker::vars_list::reinit()
{
- buffer_length= 0;
track_all= 0;
if (m_registered_sysvars.records)
my_hash_reset(&m_registered_sysvars);
@@ -310,10 +55,8 @@ void Session_sysvars_tracker::vars_list::reinit()
void Session_sysvars_tracker::vars_list::copy(vars_list* from, THD *thd)
{
- reinit();
track_all= from->track_all;
free_hash();
- buffer_length= from->buffer_length;
m_registered_sysvars= from->m_registered_sysvars;
from->init();
}
@@ -321,26 +64,20 @@ void Session_sysvars_tracker::vars_list::copy(vars_list* from, THD *thd)
/**
Inserts the variable to be tracked into m_registered_sysvars hash.
- @param node Node to be inserted.
@param svar address of the system variable
@retval false success
@retval true error
*/
-bool Session_sysvars_tracker::vars_list::insert(sysvar_node_st *node,
- const sys_var *svar,
- myf mem_flag)
+bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar)
{
- if (!node)
- {
- if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st),
- MYF(MY_WME | mem_flag))))
- {
- reinit();
- return true;
- }
- }
+ sysvar_node_st *node;
+ if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st),
+ MYF(MY_WME |
+ (mysqld_server_initialized ?
+ MY_THREAD_SPECIFIC : 0)))))
+ return true;
node->m_svar= (sys_var *)svar;
node->test_load= node->m_svar->test_load;
@@ -351,7 +88,6 @@ bool Session_sysvars_tracker::vars_list::insert(sysvar_node_st *node,
if (!search((sys_var *)svar))
{
//EOF (error is already reported)
- reinit();
return true;
}
}
@@ -373,7 +109,6 @@ bool Session_sysvars_tracker::vars_list::insert(sysvar_node_st *node,
in case of invalid/duplicate values.
@param char_set [IN] charecter set information used for string
manipulations.
- @param take_mutex [IN] take LOCK_plugin
@return
true Error
@@ -382,39 +117,24 @@ bool Session_sysvars_tracker::vars_list::insert(sysvar_node_st *node,
bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd,
LEX_STRING var_list,
bool throw_error,
- CHARSET_INFO *char_set,
- bool take_mutex)
+ CHARSET_INFO *char_set)
{
const char separator= ',';
char *token, *lasts= NULL;
size_t rest= var_list.length;
- reinit();
if (!var_list.str || var_list.length == 0)
- {
- buffer_length= 1;
return false;
- }
if(!strcmp(var_list.str, "*"))
{
track_all= true;
- buffer_length= 2;
return false;
}
- buffer_length= var_list.length + 1;
token= var_list.str;
track_all= false;
- /*
- If Lock to the plugin mutex is not acquired here itself, it results
- in having to acquire it multiple times in find_sys_var_ex for each
- token value. Hence the mutex is handled here to avoid a performance
- overhead.
- */
- if (!thd || take_mutex)
- mysql_mutex_lock(&LOCK_plugin);
for (;;)
{
sys_var *svar;
@@ -438,11 +158,10 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd,
{
track_all= true;
}
- else if ((svar=
- find_sys_var_ex(thd, var.str, var.length, throw_error, true)))
+ else if ((svar= find_sys_var(thd, var.str, var.length, throw_error)))
{
- if (insert(NULL, svar, m_mem_flag) == TRUE)
- goto error;
+ if (insert(svar) == TRUE)
+ return true;
}
else if (throw_error && thd)
{
@@ -452,31 +171,20 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd,
"be ignored.", (int)var.length, token);
}
else
- goto error;
+ return true;
if (lasts)
token= lasts + 1;
else
break;
}
- if (!thd || take_mutex)
- mysql_mutex_unlock(&LOCK_plugin);
-
return false;
-
-error:
- if (!thd || take_mutex)
- mysql_mutex_unlock(&LOCK_plugin);
- return true;
}
-bool Session_sysvars_tracker::check_var_list(THD *thd,
- LEX_STRING var_list,
- bool throw_error,
- CHARSET_INFO *char_set,
- bool take_mutex)
+bool sysvartrack_validate_value(THD *thd, const char *str, size_t len)
{
+ LEX_STRING var_list= { (char *) str, len };
const char separator= ',';
char *token, *lasts= NULL;
size_t rest= var_list.length;
@@ -489,14 +197,6 @@ bool Session_sysvars_tracker::check_var_list(THD *thd,
token= var_list.str;
- /*
- If Lock to the plugin mutex is not acquired here itself, it results
- in having to acquire it multiple times in find_sys_var_ex for each
- token value. Hence the mutex is handled here to avoid a performance
- overhead.
- */
- if (!thd || take_mutex)
- mysql_mutex_lock(&LOCK_plugin);
for (;;)
{
LEX_CSTRING var;
@@ -513,55 +213,19 @@ bool Session_sysvars_tracker::check_var_list(THD *thd,
var.length= rest;
/* Remove leading/trailing whitespace. */
- trim_whitespace(char_set, &var);
+ trim_whitespace(system_charset_info, &var);
- if(!strcmp(var.str, "*") &&
- !find_sys_var_ex(thd, var.str, var.length, throw_error, true))
- {
- if (throw_error && take_mutex && thd)
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WRONG_VALUE_FOR_VAR,
- "%.*s is not a valid system variable and will"
- "be ignored.", (int)var.length, token);
- }
- else
- {
- if (!thd || take_mutex)
- mysql_mutex_unlock(&LOCK_plugin);
- return true;
- }
- }
+ if (!strcmp(var.str, "*") && !find_sys_var(thd, var.str, var.length))
+ return true;
if (lasts)
token= lasts + 1;
else
break;
}
- if (!thd || take_mutex)
- mysql_mutex_unlock(&LOCK_plugin);
-
return false;
}
-struct name_array_filler_data
-{
- LEX_CSTRING **names;
- uint idx;
-
-};
-
-/** Collects variable references into array */
-my_bool Session_sysvars_tracker::name_array_filler(void *ptr,
- void *data_ptr)
-{
- Session_sysvars_tracker::sysvar_node_st *node=
- (Session_sysvars_tracker::sysvar_node_st *)ptr;
- name_array_filler_data *data= (struct name_array_filler_data *)data_ptr;
- if (*node->test_load)
- data->names[data->idx++]= &node->m_svar->name;
- return FALSE;
-}
/* Sorts variable references array */
static int name_array_sorter(const void *a, const void *b)
@@ -581,7 +245,8 @@ static int name_array_sorter(const void *a, const void *b)
bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf,
size_t buf_len)
{
- struct name_array_filler_data data;
+ LEX_CSTRING **names;
+ uint idx;
size_t left= buf_len;
size_t names_size= m_registered_sysvars.records * sizeof(LEX_CSTRING *);
const char separator= ',';
@@ -604,16 +269,19 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf,
return false;
}
- data.names= (LEX_CSTRING**)my_safe_alloca(names_size);
-
- if (unlikely(!data.names))
+ if (unlikely(!(names= (LEX_CSTRING**) my_safe_alloca(names_size))))
return true;
- data.idx= 0;
+ idx= 0;
mysql_mutex_lock(&LOCK_plugin);
- my_hash_iterate(&m_registered_sysvars, &name_array_filler, &data);
- DBUG_ASSERT(data.idx <= m_registered_sysvars.records);
+ for (ulong i= 0; i < m_registered_sysvars.records; i++)
+ {
+ sysvar_node_st *node= at(i);
+ if (*node->test_load)
+ names[idx++]= &node->m_svar->name;
+ }
+ DBUG_ASSERT(idx <= m_registered_sysvars.records);
/*
We check number of records again here because number of variables
@@ -626,17 +294,16 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf,
return false;
}
- my_qsort(data.names, data.idx, sizeof(LEX_CSTRING *),
- &name_array_sorter);
+ my_qsort(names, idx, sizeof(LEX_CSTRING*), &name_array_sorter);
- for(uint i= 0; i < data.idx; i++)
+ for(uint i= 0; i < idx; i++)
{
- LEX_CSTRING *nm= data.names[i];
+ LEX_CSTRING *nm= names[i];
size_t ln= nm->length + 1;
if (ln > left)
{
mysql_mutex_unlock(&LOCK_plugin);
- my_safe_afree(data.names, names_size);
+ my_safe_afree(names, names_size);
return true;
}
memcpy(buf, nm->str, nm->length);
@@ -647,58 +314,47 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf,
mysql_mutex_unlock(&LOCK_plugin);
buf--; buf[0]= '\0';
- my_safe_afree(data.names, names_size);
+ my_safe_afree(names, names_size);
return false;
}
-/**
- Enable session tracker by parsing global value of tracked variables.
- @param thd [IN] The thd handle.
+void Session_sysvars_tracker::init(THD *thd)
+{
+ mysql_mutex_assert_owner(&LOCK_global_system_variables);
+ DBUG_ASSERT(thd->variables.session_track_system_variables ==
+ global_system_variables.session_track_system_variables);
+ DBUG_ASSERT(global_system_variables.session_track_system_variables);
+ thd->variables.session_track_system_variables=
+ my_strdup(global_system_variables.session_track_system_variables,
+ MYF(MY_WME | MY_THREAD_SPECIFIC));
+}
- @retval true Error
- @retval false Success
-*/
-bool Session_sysvars_tracker::enable(THD *thd)
+void Session_sysvars_tracker::deinit(THD *thd)
{
- mysql_mutex_lock(&LOCK_plugin);
- LEX_STRING tmp;
- tmp.str= global_system_variables.session_track_system_variables;
- tmp.length= safe_strlen(tmp.str);
- if (tool_list->parse_var_list(thd, tmp,
- true, thd->charset(), false) == true)
- {
- mysql_mutex_unlock(&LOCK_plugin);
- return true;
- }
- mysql_mutex_unlock(&LOCK_plugin);
- orig_list->copy(tool_list, thd);
- m_enabled= true;
-
- return false;
+ my_free(thd->variables.session_track_system_variables);
+ thd->variables.session_track_system_variables= 0;
}
/**
- Check system variable name(s).
-
- @note This function is called from the ON_CHECK() function of the
- session_track_system_variables' sys_var class.
+ Enable session tracker by parsing global value of tracked variables.
@param thd [IN] The thd handle.
- @param var [IN] A pointer to set_var holding the specified list of
- system variable names.
@retval true Error
@retval false Success
*/
-inline bool Session_sysvars_tracker::check_str(THD *thd, LEX_STRING *val)
+bool Session_sysvars_tracker::enable(THD *thd)
{
- return Session_sysvars_tracker::check_var_list(thd, *val, true,
- thd->charset(), true);
+ orig_list.reinit();
+ m_parsed= false;
+ m_enabled= thd->variables.session_track_system_variables &&
+ *thd->variables.session_track_system_variables;
+ return false;
}
@@ -708,6 +364,9 @@ inline bool Session_sysvars_tracker::check_str(THD *thd, LEX_STRING *val)
Session_sysvars_tracker::vars_list::copy updating the hash in orig_list
which represents the system variables to be tracked.
+ We are doing via tool list because there possible errors with memory
+ in this case value will be unchanged.
+
@note This function is called from the ON_UPDATE() function of the
session_track_system_variables' sys_var class.
@@ -719,37 +378,43 @@ inline bool Session_sysvars_tracker::check_str(THD *thd, LEX_STRING *val)
bool Session_sysvars_tracker::update(THD *thd, set_var *var)
{
- /*
- We are doing via tool list because there possible errors with memory
- in this case value will be unchanged.
- */
- tool_list->reinit();
- if (tool_list->parse_var_list(thd, var->save_result.string_value, true,
- thd->charset(), true))
+ vars_list tool_list;
+ void *copy= var->save_result.string_value.str ?
+ my_memdup(var->save_result.string_value.str,
+ var->save_result.string_value.length + 1,
+ MYF(MY_WME | MY_THREAD_SPECIFIC)) :
+ my_strdup("", MYF(MY_WME | MY_THREAD_SPECIFIC));
+
+ if (!copy)
return true;
- orig_list->copy(tool_list, thd);
- return false;
-}
+ if (tool_list.parse_var_list(thd, var->save_result.string_value, true,
+ thd->charset()))
+ {
+ my_free(copy);
+ return true;
+ }
+
+ my_free(thd->variables.session_track_system_variables);
+ thd->variables.session_track_system_variables= static_cast<char*>(copy);
-/*
- Function and structure to support storing variables from hash to the buffer.
-*/
+ m_parsed= true;
+ orig_list.copy(&tool_list, thd);
+ orig_list.construct_var_list(thd->variables.session_track_system_variables,
+ var->save_result.string_value.length + 1);
+ return false;
+}
-struct st_store_variable_param
-{
- THD *thd;
- String *buf;
-};
-my_bool Session_sysvars_tracker::store_variable(void *ptr, void *data_ptr)
+bool Session_sysvars_tracker::vars_list::store(THD *thd, String *buf)
{
- Session_sysvars_tracker::sysvar_node_st *node=
- (Session_sysvars_tracker::sysvar_node_st *)ptr;
- if (node->m_changed)
+ for (ulong i= 0; i < m_registered_sysvars.records; i++)
{
- THD *thd= ((st_store_variable_param *)data_ptr)->thd;
- String *buf= ((st_store_variable_param *)data_ptr)->buf;
+ sysvar_node_st *node= at(i);
+
+ if (!node->m_changed)
+ continue;
+
char val_buf[SHOW_VAR_FUNC_BUFF_SIZE];
SHOW_VAR show;
CHARSET_INFO *charset;
@@ -758,7 +423,7 @@ my_bool Session_sysvars_tracker::store_variable(void *ptr, void *data_ptr)
if (!*node->test_load)
{
mysql_mutex_unlock(&LOCK_plugin);
- return false;
+ continue;
}
sys_var *svar= node->m_svar;
bool is_plugin= svar->cast_pluginvar();
@@ -803,11 +468,6 @@ my_bool Session_sysvars_tracker::store_variable(void *ptr, void *data_ptr)
return false;
}
-bool Session_sysvars_tracker::vars_list::store(THD *thd, String *buf)
-{
- st_store_variable_param data= {thd, buf};
- return my_hash_iterate(&m_registered_sysvars, &store_variable, &data);
-}
/**
Store the data for changed system variables in the specified buffer.
@@ -823,13 +483,13 @@ bool Session_sysvars_tracker::vars_list::store(THD *thd, String *buf)
bool Session_sysvars_tracker::store(THD *thd, String *buf)
{
- if (!orig_list->is_enabled())
+ if (!orig_list.is_enabled())
return false;
- if (orig_list->store(thd, buf))
+ if (orig_list.store(thd, buf))
return true;
- reset();
+ orig_list.reset();
return false;
}
@@ -844,14 +504,27 @@ bool Session_sysvars_tracker::store(THD *thd, String *buf)
void Session_sysvars_tracker::mark_as_changed(THD *thd,
LEX_CSTRING *var)
{
- sysvar_node_st *node= NULL;
+ sysvar_node_st *node;
sys_var *svar= (sys_var *)var;
+
+ if (!m_parsed)
+ {
+ DBUG_ASSERT(thd->variables.session_track_system_variables);
+ LEX_STRING tmp= { thd->variables.session_track_system_variables,
+ strlen(thd->variables.session_track_system_variables) };
+ if (orig_list.parse_var_list(thd, tmp, true, thd->charset()))
+ {
+ orig_list.reinit();
+ return;
+ }
+ m_parsed= true;
+ }
+
/*
Check if the specified system variable is being tracked, if so
mark it as changed and also set the class's m_changed flag.
*/
- if (orig_list->is_enabled() &&
- (node= (sysvar_node_st *) (orig_list->insert_or_search(node, svar))))
+ if (orig_list.is_enabled() && (node= orig_list.insert_or_search(svar)))
{
node->m_changed= true;
State_tracker::mark_as_changed(thd, var);
@@ -878,63 +551,41 @@ uchar *Session_sysvars_tracker::sysvars_get_key(const char *entry,
}
-/* Function to support resetting hash nodes for the variables */
-
-my_bool Session_sysvars_tracker::reset_variable(void *ptr,
- void *data_ptr)
-{
- ((Session_sysvars_tracker::sysvar_node_st *)ptr)->m_changed= false;
- return false;
-}
-
void Session_sysvars_tracker::vars_list::reset()
{
- my_hash_iterate(&m_registered_sysvars, &reset_variable, NULL);
+ for (ulong i= 0; i < m_registered_sysvars.records; i++)
+ at(i)->m_changed= false;
}
-/**
- Prepare/reset the m_registered_sysvars hash for next statement.
-*/
-void Session_sysvars_tracker::reset()
+bool sysvartrack_global_update(THD *thd, char *str, size_t len)
{
-
- orig_list->reset();
- m_changed= false;
+ LEX_STRING tmp= { str, len };
+ Session_sysvars_tracker::vars_list dummy;
+ if (!dummy.parse_var_list(thd, tmp, false, system_charset_info))
+ {
+ dummy.construct_var_list(str, len + 1);
+ return false;
+ }
+ return true;
}
-static Session_sysvars_tracker* sysvar_tracker(THD *thd)
-{
- return (Session_sysvars_tracker*)
- thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER);
-}
-bool sysvartrack_validate_value(THD *thd, const char *str, size_t len)
-{
- LEX_STRING tmp= {(char *)str, len};
- return Session_sysvars_tracker::server_init_check(thd, system_charset_info,
- tmp);
-}
-bool sysvartrack_reprint_value(THD *thd, char *str, size_t len)
+int session_tracker_init()
{
- LEX_STRING tmp= {str, len};
- return Session_sysvars_tracker::server_init_process(thd,
- system_charset_info,
- tmp);
-}
-bool sysvartrack_update(THD *thd, set_var *var)
-{
- return sysvar_tracker(thd)->update(thd, var);
-}
-size_t sysvartrack_value_len(THD *thd)
-{
- return sysvar_tracker(thd)->get_buffer_length();
-}
-bool sysvartrack_value_construct(THD *thd, char *val, size_t len)
-{
- return sysvar_tracker(thd)->construct_var_list(val, len);
+ DBUG_ASSERT(global_system_variables.session_track_system_variables);
+ if (sysvartrack_validate_value(0,
+ global_system_variables.session_track_system_variables,
+ strlen(global_system_variables.session_track_system_variables)))
+ {
+ sql_print_error("The variable session_track_system_variables has "
+ "invalid values.");
+ return 1;
+ }
+ return 0;
}
+
///////////////////////////////////////////////////////////////////////////////
/**
@@ -991,37 +642,12 @@ bool Current_schema_tracker::store(THD *thd, String *buf)
/* Length and current schema name */
buf->q_net_store_data((const uchar *)thd->db.str, thd->db.length);
- reset();
-
return false;
}
-/**
- Reset the m_changed flag for next statement.
-
- @return void
-*/
-
-void Current_schema_tracker::reset()
-{
- m_changed= false;
-}
-
-
///////////////////////////////////////////////////////////////////////////////
-
-Transaction_state_tracker::Transaction_state_tracker()
-{
- m_enabled = false;
- tx_changed = TX_CHG_NONE;
- tx_curr_state =
- tx_reported_state= TX_EMPTY;
- tx_read_flags = TX_READ_INHERIT;
- tx_isol_level = TX_ISOL_INHERIT;
-}
-
/**
Enable/disable the tracker based on @@session_track_transaction_info.
@@ -1331,25 +957,14 @@ bool Transaction_state_tracker::store(THD *thd, String *buf)
}
}
- reset();
+ tx_reported_state= tx_curr_state;
+ tx_changed= TX_CHG_NONE;
return false;
}
/**
- Reset the m_changed flag for next statement.
-*/
-
-void Transaction_state_tracker::reset()
-{
- m_changed= false;
- tx_reported_state= tx_curr_state;
- tx_changed= TX_CHG_NONE;
-}
-
-
-/**
Helper function: turn table info into table access flag.
Accepts table lock type and engine type flag (transactional/
non-transactional), and returns the corresponding access flag
@@ -1518,11 +1133,6 @@ void Transaction_state_tracker::set_isol_level(THD *thd,
///////////////////////////////////////////////////////////////////////////////
-Session_state_change_tracker::Session_state_change_tracker()
-{
- m_changed= false;
-}
-
/**
@Enable/disable the tracker based on @@session_track_state_change value.
@@ -1560,106 +1170,15 @@ bool Session_state_change_tracker::store(THD *thd, String *buf)
/* Length of the overall entity (1 byte) */
buf->q_append('\1');
- DBUG_ASSERT(is_state_changed(thd));
+ DBUG_ASSERT(is_changed());
buf->q_append('1');
- reset();
-
return false;
}
-
-/**
- Reset the m_changed flag for next statement.
-*/
-
-void Session_state_change_tracker::reset()
-{
- m_changed= false;
-}
-
-
-/**
- Find if there is a session state change.
-*/
-
-bool Session_state_change_tracker::is_state_changed(THD *)
-{
- return m_changed;
-}
-
///////////////////////////////////////////////////////////////////////////////
/**
- @brief Initialize session tracker objects.
-*/
-
-Session_tracker::Session_tracker()
-{
- /* track data ID fit into one byte in net coding */
- compile_time_assert(SESSION_TRACK_always_at_the_end < 251);
- /* one tracker could serv several tracking data */
- compile_time_assert((uint)SESSION_TRACK_always_at_the_end >=
- (uint)SESSION_TRACKER_END);
-
- for (int i= 0; i < SESSION_TRACKER_END; i++)
- m_trackers[i]= NULL;
-}
-
-
-/**
- @brief Enables the tracker objects.
-
- @param thd [IN] The thread handle.
-
- @return void
-*/
-
-void Session_tracker::enable(THD *thd)
-{
- /*
- Originally and correctly this allocation was in the constructor and
- deallocation in the destructor, but in this case memory counting
- system works incorrectly (for example in INSERT DELAYED thread)
- */
- deinit();
- m_trackers[SESSION_SYSVARS_TRACKER]=
- new (std::nothrow) Session_sysvars_tracker();
- m_trackers[CURRENT_SCHEMA_TRACKER]=
- new (std::nothrow) Current_schema_tracker;
- m_trackers[SESSION_STATE_CHANGE_TRACKER]=
- new (std::nothrow) Session_state_change_tracker;
- m_trackers[SESSION_GTIDS_TRACKER]=
- new (std::nothrow) Not_implemented_tracker;
- m_trackers[TRANSACTION_INFO_TRACKER]=
- new (std::nothrow) Transaction_state_tracker;
-
- for (int i= 0; i < SESSION_TRACKER_END; i++)
- m_trackers[i]->enable(thd);
-}
-
-
-/**
- Method called during the server startup to verify the contents
- of @@session_track_system_variables.
-
- @retval false Success
- @retval true Failure
-*/
-
-bool Session_tracker::server_boot_verify(CHARSET_INFO *char_set)
-{
- bool result;
- LEX_STRING tmp;
- tmp.str= global_system_variables.session_track_system_variables;
- tmp.length= safe_strlen(tmp.str);
- result=
- Session_sysvars_tracker::server_init_check(NULL, char_set, tmp);
- return result;
-}
-
-
-/**
@brief Store all change information in the specified buffer.
@param thd [IN] The thd handle.
@@ -1671,6 +1190,12 @@ void Session_tracker::store(THD *thd, String *buf)
{
size_t start;
+ /* track data ID fit into one byte in net coding */
+ compile_time_assert(SESSION_TRACK_always_at_the_end < 251);
+ /* one tracker could serv several tracking data */
+ compile_time_assert((uint) SESSION_TRACK_always_at_the_end >=
+ (uint) SESSION_TRACKER_END);
+
/*
Probably most track result will fit in 251 byte so lets made it at
least efficient. We allocate 1 byte for length and then will move
@@ -1682,11 +1207,15 @@ void Session_tracker::store(THD *thd, String *buf)
/* Get total length. */
for (int i= 0; i < SESSION_TRACKER_END; i++)
{
- if (m_trackers[i]->is_changed() &&
- m_trackers[i]->store(thd, buf))
+ if (m_trackers[i]->is_changed())
{
- buf->length(start); // it is safer to have 0-length block in case of error
- return;
+ if (m_trackers[i]->store(thd, buf))
+ {
+ // it is safer to have 0-length block in case of error
+ buf->length(start);
+ return;
+ }
+ m_trackers[i]->reset_changed();
}
}
@@ -1706,5 +1235,3 @@ void Session_tracker::store(THD *thd, String *buf)
net_store_length(data - 1, length);
}
-
-#endif //EMBEDDED_LIBRARY
diff --git a/sql/session_tracker.h b/sql/session_tracker.h
index 684692aae0c..226b026d590 100644
--- a/sql/session_tracker.h
+++ b/sql/session_tracker.h
@@ -32,7 +32,6 @@ enum enum_session_tracker
SESSION_SYSVARS_TRACKER, /* Session system variables */
CURRENT_SCHEMA_TRACKER, /* Current schema */
SESSION_STATE_CHANGE_TRACKER,
- SESSION_GTIDS_TRACKER, /* Tracks GTIDs */
TRANSACTION_INFO_TRACKER, /* Transaction state */
SESSION_TRACKER_END /* must be the last */
};
@@ -67,17 +66,12 @@ protected:
*/
bool m_enabled;
+private:
/** Has the session state type changed ? */
bool m_changed;
public:
- /** Constructor */
- State_tracker() : m_enabled(false), m_changed(false)
- {}
-
- /** Destructor */
- virtual ~State_tracker()
- {}
+ virtual ~State_tracker() {}
/** Getters */
bool is_enabled() const
@@ -86,8 +80,20 @@ public:
bool is_changed() const
{ return m_changed; }
- /** Called in the constructor of THD*/
- virtual bool enable(THD *thd)= 0;
+ void reset_changed() { m_changed= false; }
+
+ /**
+ Called by THD::init() when new connection is being created
+
+ We may inherit m_changed from previous connection served by this THD if
+ connection was broken or client didn't have session tracking capability.
+ Thus we have to reset it here.
+ */
+ virtual bool enable(THD *thd)
+ {
+ reset_changed();
+ return update(thd, 0);
+ }
/** To be invoked when the tracker's system variable is updated (ON_UPDATE).*/
virtual bool update(THD *thd, set_var *var)= 0;
@@ -99,74 +105,156 @@ public:
virtual void mark_as_changed(THD *thd, LEX_CSTRING *name);
};
-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, set_var *var);
-size_t sysvartrack_value_len(THD *thd);
-bool sysvartrack_value_construct(THD *thd, char *val, size_t len);
-
/**
- Session_tracker
+ Session_sysvars_tracker
- This class holds an object each for all tracker classes and provides
- methods necessary for systematic detection and generation of session
- state change information.
+ This is a tracker class that enables & manages the tracking of session
+ system variables. It internally maintains a hash of user supplied variable
+ references and a boolean field to store if the variable was changed by the
+ last statement.
*/
-class Session_tracker
+class Session_sysvars_tracker: public State_tracker
{
-private:
- State_tracker *m_trackers[SESSION_TRACKER_END];
+ struct sysvar_node_st {
+ sys_var *m_svar;
+ bool *test_load;
+ bool m_changed;
+ };
- /* The following two functions are private to disable copying. */
- Session_tracker(Session_tracker const &other)
- {
- DBUG_ASSERT(FALSE);
- }
- Session_tracker& operator= (Session_tracker const &rhs)
+ class vars_list
{
- DBUG_ASSERT(FALSE);
- return *this;
- }
+ /**
+ Registered system variables. (@@session_track_system_variables)
+ A hash to store the name of all the system variables specified by the
+ user.
+ */
+ HASH m_registered_sysvars;
+ /**
+ If TRUE then we want to check all session variable.
+ */
+ bool track_all;
+ void init()
+ {
+ my_hash_init(&m_registered_sysvars, &my_charset_bin, 0, 0, 0,
+ (my_hash_get_key) sysvars_get_key, my_free,
+ HASH_UNIQUE | (mysqld_server_initialized ?
+ HASH_THREAD_SPECIFIC : 0));
+ }
+ void free_hash()
+ {
+ DBUG_ASSERT(my_hash_inited(&m_registered_sysvars));
+ my_hash_free(&m_registered_sysvars);
+ }
-public:
+ sysvar_node_st *search(const sys_var *svar)
+ {
+ return reinterpret_cast<sysvar_node_st*>(
+ my_hash_search(&m_registered_sysvars,
+ reinterpret_cast<const uchar*>(&svar),
+ sizeof(sys_var*)));
+ }
- Session_tracker();
- ~Session_tracker()
- {
- deinit();
- }
+ sysvar_node_st *at(ulong i)
+ {
+ DBUG_ASSERT(i < m_registered_sysvars.records);
+ return reinterpret_cast<sysvar_node_st*>(
+ my_hash_element(&m_registered_sysvars, i));
+ }
+ public:
+ vars_list(): track_all(false) { init(); }
+ ~vars_list() { if (my_hash_inited(&m_registered_sysvars)) free_hash(); }
+ void deinit() { free_hash(); }
- /* trick to make happy memory accounting system */
- void deinit()
- {
- for (int i= 0; i < SESSION_TRACKER_END; i++)
+ sysvar_node_st *insert_or_search(const sys_var *svar)
{
- if (m_trackers[i])
- delete m_trackers[i];
- m_trackers[i]= NULL;
+ sysvar_node_st *res= search(svar);
+ if (!res)
+ {
+ if (track_all)
+ {
+ insert(svar);
+ return search(svar);
+ }
+ }
+ return res;
}
- }
- void enable(THD *thd);
- static bool server_boot_verify(CHARSET_INFO *char_set);
+ bool insert(const sys_var *svar);
+ void reinit();
+ void reset();
+ inline bool is_enabled()
+ {
+ return track_all || m_registered_sysvars.records;
+ }
+ void copy(vars_list* from, THD *thd);
+ bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error,
+ CHARSET_INFO *char_set);
+ bool construct_var_list(char *buf, size_t buf_len);
+ bool store(THD *thd, String *buf);
+ };
+ /**
+ Two objects of vars_list type are maintained to manage
+ various operations.
+ */
+ vars_list orig_list;
+ bool m_parsed;
- /** Returns the pointer to the tracker object for the specified tracker. */
- inline State_tracker *get_tracker(enum_session_tracker tracker) const
- {
- return m_trackers[tracker];
- }
+public:
+ void init(THD *thd);
+ void deinit(THD *thd);
+ bool enable(THD *thd);
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
+ void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name);
+ void deinit() { orig_list.deinit(); }
+ /* callback */
+ static uchar *sysvars_get_key(const char *entry, size_t *length,
+ my_bool not_used __attribute__((unused)));
- inline void mark_as_changed(THD *thd, enum enum_session_tracker tracker,
- LEX_CSTRING *data)
- {
- if (m_trackers[tracker]->is_enabled())
- m_trackers[tracker]->mark_as_changed(thd, data);
- }
+ friend bool sysvartrack_global_update(THD *thd, char *str, size_t len);
+};
- void store(THD *thd, String *main_buf);
+bool sysvartrack_validate_value(THD *thd, const char *str, size_t len);
+bool sysvartrack_global_update(THD *thd, char *str, size_t len);
+
+
+/**
+ Current_schema_tracker,
+
+ This is a tracker class that enables & manages the tracking of current
+ schema for a particular connection.
+*/
+
+class Current_schema_tracker: public State_tracker
+{
+public:
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
+};
+
+
+/*
+ Session_state_change_tracker
+
+ This is a boolean tracker class that will monitor any change that contributes
+ to a session state change.
+ Attributes that contribute to session state change include:
+ - Successful change to System variables
+ - User defined variables assignments
+ - temporary tables created, altered or deleted
+ - prepared statements added or removed
+ - change in current database
+ - change of current role
+*/
+
+class Session_state_change_tracker: public State_tracker
+{
+public:
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
};
@@ -231,14 +319,21 @@ enum enum_session_track_transaction_info {
class Transaction_state_tracker : public State_tracker
{
-private:
/** Helper function: turn table info into table access flag */
enum_tx_state calc_trx_state(THD *thd, thr_lock_type l, bool has_trx);
public:
- /** Constructor */
- Transaction_state_tracker();
+
bool enable(THD *thd)
- { return update(thd, NULL); }
+ {
+ m_enabled= false;
+ tx_changed= TX_CHG_NONE;
+ tx_curr_state= TX_EMPTY;
+ tx_reported_state= TX_EMPTY;
+ tx_read_flags= TX_READ_INHERIT;
+ tx_isol_level= TX_ISOL_INHERIT;
+ return State_tracker::enable(thd);
+ }
+
bool update(THD *thd, set_var *var);
bool store(THD *thd, String *buf);
@@ -276,8 +371,6 @@ private:
/** isolation level */
enum enum_tx_isol_level tx_isol_level;
- void reset();
-
inline void update_change_flags(THD *thd)
{
tx_changed &= uint(~TX_CHG_STATE);
@@ -289,11 +382,67 @@ private:
#define TRANSACT_TRACKER(X) \
do { if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) \
- {((Transaction_state_tracker *) \
- thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER)) \
- ->X; } } while(0)
+ thd->session_tracker.transaction_info.X; } while(0)
#define SESSION_TRACKER_CHANGED(A,B,C) \
thd->session_tracker.mark_as_changed(A,B,C)
+
+
+/**
+ Session_tracker
+
+ This class holds an object each for all tracker classes and provides
+ methods necessary for systematic detection and generation of session
+ state change information.
+*/
+
+class Session_tracker
+{
+ State_tracker *m_trackers[SESSION_TRACKER_END];
+
+ /* The following two functions are private to disable copying. */
+ Session_tracker(Session_tracker const &other)
+ {
+ DBUG_ASSERT(FALSE);
+ }
+ Session_tracker& operator= (Session_tracker const &rhs)
+ {
+ DBUG_ASSERT(FALSE);
+ return *this;
+ }
+
+public:
+ Current_schema_tracker current_schema;
+ Session_state_change_tracker state_change;
+ Transaction_state_tracker transaction_info;
+ Session_sysvars_tracker sysvars;
+
+ Session_tracker()
+ {
+ m_trackers[SESSION_SYSVARS_TRACKER]= &sysvars;
+ m_trackers[CURRENT_SCHEMA_TRACKER]= &current_schema;
+ m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change;
+ m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info;
+ }
+
+ void enable(THD *thd)
+ {
+ for (int i= 0; i < SESSION_TRACKER_END; i++)
+ m_trackers[i]->enable(thd);
+ }
+
+ inline void mark_as_changed(THD *thd, enum enum_session_tracker tracker,
+ LEX_CSTRING *data)
+ {
+ if (m_trackers[tracker]->is_enabled())
+ m_trackers[tracker]->mark_as_changed(thd, data);
+ }
+
+
+ void store(THD *thd, String *main_buf);
+};
+
+
+int session_tracker_init();
#else
#define TRANSACT_TRACKER(X) do{}while(0)
diff --git a/sql/set_var.cc b/sql/set_var.cc
index de9bda3d067..ae4e712c77d 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1016,13 +1016,13 @@ int set_var_collation_client::update(THD *thd)
/* Mark client collation variables as changed */
#ifndef EMBEDDED_LIBRARY
- if (thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled())
+ if (thd->session_tracker.sysvars.is_enabled())
{
- thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->
+ thd->session_tracker.sysvars.
mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_client_ptr);
- thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->
+ thd->session_tracker.sysvars.
mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_results_ptr);
- thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->
+ thd->session_tracker.sysvars.
mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_connection_ptr);
}
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
diff --git a/sql/set_var.h b/sql/set_var.h
index 8a82e07fd6b..5f9720f0d5a 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -407,7 +407,8 @@ extern SHOW_COMP_OPTION have_openssl;
SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond);
-sys_var *find_sys_var(THD *thd, const char *str, size_t length=0);
+sys_var *find_sys_var(THD *thd, const char *str, size_t length= 0,
+ bool throw_error= false);
int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free);
#define SYSVAR_AUTOSIZE(VAR,VAL) \
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index cdda49c5796..ca9985c172e 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -30,6 +30,10 @@
#define SIGNAL_FMT "signal %d"
#endif
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
/*
We are handling signals/exceptions in this file.
Any global variables we read should be 'volatile sig_atomic_t'
@@ -44,6 +48,43 @@ extern volatile sig_atomic_t ld_assume_kernel_is_set;
extern const char *optimizer_switch_names[];
+static inline void output_core_info()
+{
+ /* proc is optional on some BSDs so it can't hurt to look */
+#ifdef HAVE_READLINK
+ char buff[PATH_MAX];
+ ssize_t len;
+ int fd;
+ if ((len= readlink("/proc/self/cwd", buff, sizeof(buff))) >= 0)
+ {
+ my_safe_printf_stderr("Writing a core file...\nWorking directory at %.*s\n",
+ (int) len, buff);
+ }
+ if ((fd= my_open("/proc/self/limits", O_RDONLY, MYF(0))) >= 0)
+ {
+ my_safe_printf_stderr("Resource Limits:\n");
+ while ((len= my_read(fd, (uchar*)buff, sizeof(buff), MYF(0))) > 0)
+ {
+ my_write_stderr(buff, len);
+ }
+ my_close(fd, MYF(0));
+ }
+#ifdef __linux__
+ if ((fd= my_open("/proc/sys/kernel/core_pattern", O_RDONLY, MYF(0))) >= 0)
+ {
+ len= my_read(fd, (uchar*)buff, sizeof(buff), MYF(0));
+ my_safe_printf_stderr("Core pattern: %.*s\n", (int) len, buff);
+ my_close(fd, MYF(0));
+ }
+#endif
+#else
+ char buff[80];
+ my_getwd(buff, sizeof(buff), 0);
+ my_safe_printf_stderr("Writing a core file at %s\n", buff);
+ fflush(stderr);
+#endif
+}
+
/**
* Handler for fatal signals on POSIX, exception handler on Windows.
*
@@ -295,13 +336,10 @@ extern "C" sig_handler handle_fatal_signal(int sig)
}
#endif
+ output_core_info();
#ifdef HAVE_WRITE_CORE
if (test_flags & TEST_CORE_ON_SIGNAL)
{
- char buff[80];
- my_getwd(buff, sizeof(buff), 0);
- my_safe_printf_stderr("Writing a core file at %s\n", buff);
- fflush(stderr);
my_write_core(sig);
}
#endif
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index d8b5b7364a9..87cfb2b95bb 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -8817,13 +8817,13 @@ static const char *command_array[]=
"LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT",
"CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE",
"CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE",
- "DELETE VERSIONING ROWS"
+ "DELETE HISTORY"
};
static uint command_lengths[]=
{
6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9,
- 14, 13, 11, 5, 7, 17, 22,
+ 14, 13, 11, 5, 7, 17, 14,
};
diff --git a/sql/sql_analyze_stmt.cc b/sql/sql_analyze_stmt.cc
index b66d69334f0..61ca7c9a7af 100644
--- a/sql/sql_analyze_stmt.cc
+++ b/sql/sql_analyze_stmt.cc
@@ -45,7 +45,7 @@ void Filesort_tracker::print_json_members(Json_writer *writer)
else if (r_limit == 0)
writer->add_str(varied_str);
else
- writer->add_ll((longlong) rint(r_limit));
+ writer->add_ll(r_limit);
}
writer->add_member("r_used_priority_queue");
@@ -61,13 +61,13 @@ void Filesort_tracker::print_json_members(Json_writer *writer)
if (!get_r_loops())
writer->add_member("r_output_rows").add_null();
else
- writer->add_member("r_output_rows").add_ll((longlong) rint(r_output_rows /
- get_r_loops()));
+ writer->add_member("r_output_rows").add_ll(
+ (longlong) rint((double)r_output_rows / get_r_loops()));
if (sort_passes)
{
- writer->add_member("r_sort_passes").add_ll((longlong) rint(sort_passes /
- get_r_loops()));
+ writer->add_member("r_sort_passes").add_ll(
+ (longlong) rint((double)sort_passes / get_r_loops()));
}
if (sort_buffer_size != 0)
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b346ebb92c1..b01edf6259b 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -600,7 +600,7 @@ extern "C" void thd_kill_timeout(THD* thd)
thd->awake(KILL_TIMEOUT);
}
-THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
+THD::THD(my_thread_id id, bool is_wsrep_applier)
:Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0),
rli_fake(0), rgi_fake(0), rgi_slave(NULL),
@@ -808,7 +808,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
/* Call to init() below requires fully initialized Open_tables_state. */
reset_open_tables_state(this);
- init(skip_global_sys_var_lock);
+ init();
#if defined(ENABLED_PROFILING)
profiling.set_thd(this);
#endif
@@ -1216,11 +1216,10 @@ const Type_handler *THD::type_handler_for_date() const
Init common variables that has to be reset on start and on change_user
*/
-void THD::init(bool skip_lock)
+void THD::init()
{
DBUG_ENTER("thd::init");
- if (!skip_lock)
- mysql_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_global_system_variables);
plugin_thdvar_init(this);
/*
plugin_thd_var_init() sets variables= global_system_variables, which
@@ -1233,8 +1232,7 @@ void THD::init(bool skip_lock)
::strmake(default_master_connection_buff,
global_system_variables.default_master_connection.str,
variables.default_master_connection.length);
- if (!skip_lock)
- mysql_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
user_time.val= start_time= start_time_sec_part= 0;
@@ -1723,7 +1721,7 @@ THD::~THD()
/* trick to make happy memory accounting system */
#ifndef EMBEDDED_LIBRARY
- session_tracker.deinit();
+ session_tracker.sysvars.deinit();
#endif //EMBEDDED_LIBRARY
if (status_var.local_memory_used != 0)
@@ -7151,12 +7149,12 @@ void THD::set_last_commit_gtid(rpl_gtid &gtid)
#endif
m_last_commit_gtid= gtid;
#ifndef EMBEDDED_LIBRARY
- if (changed_gtid &&
- session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled())
+ if (changed_gtid && session_tracker.sysvars.is_enabled())
{
- session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->
+ DBUG_ASSERT(current_thd == this);
+ session_tracker.sysvars.
mark_as_changed(this, (LEX_CSTRING*)Sys_last_gtid_ptr);
- }
+ }
#endif
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index da21b9cb108..1266e1777ce 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3239,17 +3239,12 @@ public:
/**
@param id thread identifier
@param is_wsrep_applier thread type
- @param skip_lock instruct whether @c LOCK_global_system_variables
- is already locked, to not acquire it then.
*/
- THD(my_thread_id id, bool is_wsrep_applier= false, bool skip_lock= false);
+ THD(my_thread_id id, bool is_wsrep_applier= false);
~THD();
- /**
- @param skip_lock instruct whether @c LOCK_global_system_variables
- is already locked, to not acquire it then.
- */
- void init(bool skip_lock= false);
+
+ void init();
/*
Initialize memory roots necessary for query processing and (!)
pre-allocate memory for it. We can't do that in THD constructor because
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index e1a6420846d..b0544300f1d 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -7640,8 +7640,7 @@ bool LEX::set_system_variable(THD *thd, enum_var_type var_type,
{
sys_var *tmp;
if (unlikely(check_reserved_words(name1)) ||
- unlikely(!(tmp= find_sys_var_ex(thd, name2->str, name2->length, true,
- false))))
+ unlikely(!(tmp= find_sys_var(thd, name2->str, name2->length, true))))
{
my_error(ER_UNKNOWN_STRUCTURED_VARIABLE, MYF(0),
(int) name1->length, name1->str);
@@ -8208,7 +8207,7 @@ int set_statement_var_if_exists(THD *thd, const char *var_name,
my_error(ER_SP_BADSTATEMENT, MYF(0), "[NO]WAIT");
return 1;
}
- if ((sysvar= find_sys_var_ex(thd, var_name, var_name_length, true, false)))
+ if ((sysvar= find_sys_var(thd, var_name, var_name_length, true)))
{
Item *item= new (thd->mem_root) Item_uint(thd, value);
set_var *var= new (thd->mem_root) set_var(thd, OPT_SESSION, sysvar,
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 4b23d87feb1..58c1dd3dfae 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -968,6 +968,7 @@ public:
bool union_needs_tmp_table();
void set_unique_exclude();
+ bool check_distinct_in_union();
friend struct LEX;
friend int subselect_union_engine::exec();
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 21767b4de96..82b4e85e6b3 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -2834,37 +2834,25 @@ static void update_func_double(THD *thd, struct st_mysql_sys_var *var,
System Variables support
****************************************************************************/
-sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length,
- bool throw_error, bool locked)
+sys_var *find_sys_var(THD *thd, const char *str, size_t length,
+ bool throw_error)
{
sys_var *var;
- sys_var_pluginvar *pi= NULL;
- plugin_ref plugin;
- DBUG_ENTER("find_sys_var_ex");
+ sys_var_pluginvar *pi;
+ DBUG_ENTER("find_sys_var");
DBUG_PRINT("enter", ("var '%.*s'", (int)length, str));
- if (!locked)
- mysql_mutex_lock(&LOCK_plugin);
mysql_prlock_rdlock(&LOCK_system_variables_hash);
if ((var= intern_find_sys_var(str, length)) &&
(pi= var->cast_pluginvar()))
{
- mysql_prlock_unlock(&LOCK_system_variables_hash);
- LEX *lex= thd ? thd->lex : 0;
- if (!(plugin= intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
+ mysql_mutex_lock(&LOCK_plugin);
+ if (!intern_plugin_lock(thd ? thd->lex : 0, plugin_int_to_ref(pi->plugin),
+ PLUGIN_IS_READY))
var= NULL; /* failed to lock it, it must be uninstalling */
- else
- if (!(plugin_state(plugin) & PLUGIN_IS_READY))
- {
- /* initialization not completed */
- var= NULL;
- intern_plugin_unlock(lex, plugin);
- }
- }
- else
- mysql_prlock_unlock(&LOCK_system_variables_hash);
- if (!locked)
mysql_mutex_unlock(&LOCK_plugin);
+ }
+ mysql_prlock_unlock(&LOCK_system_variables_hash);
if (unlikely(!throw_error && !var))
my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0),
@@ -2873,11 +2861,6 @@ sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length,
}
-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.
@@ -3161,6 +3144,11 @@ void plugin_thdvar_init(THD *thd)
thd->variables.enforced_table_plugin= NULL;
cleanup_variables(&thd->variables);
+ /* This and all other variable cleanups are here for COM_CHANGE_USER :( */
+#ifndef EMBEDDED_LIBRARY
+ thd->session_tracker.sysvars.deinit(thd);
+#endif
+
thd->variables= global_system_variables;
/* we are going to allocate these lazily */
@@ -3182,6 +3170,9 @@ void plugin_thdvar_init(THD *thd)
intern_plugin_unlock(NULL, old_enforced_table_plugin);
mysql_mutex_unlock(&LOCK_plugin);
+#ifndef EMBEDDED_LIBRARY
+ thd->session_tracker.sysvars.init(thd);
+#endif
DBUG_VOID_RETURN;
}
@@ -3247,6 +3238,10 @@ void plugin_thdvar_cleanup(THD *thd)
plugin_ref *list;
DBUG_ENTER("plugin_thdvar_cleanup");
+#ifndef EMBEDDED_LIBRARY
+ thd->session_tracker.sysvars.deinit(thd);
+#endif
+
mysql_mutex_lock(&LOCK_plugin);
unlock_variables(thd, &thd->variables);
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index 4e899e18f9b..01ec0563050 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -196,9 +196,6 @@ extern void sync_dynamic_session_variables(THD* thd, bool global_lock);
extern bool plugin_dl_foreach(THD *thd, const LEX_CSTRING *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);
-
extern void sync_dynamic_session_variables(THD* thd, bool global_lock);
#endif
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 4d904199efc..a0cde02be65 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2318,6 +2318,16 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
!(sql_mode & MODE_NO_FIELD_OPTIONS))
packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
}
+
+ if (field->comment.length)
+ {
+ packet->append(STRING_WITH_LEN(" COMMENT "));
+ append_unescaped(packet, field->comment.str, field->comment.length);
+ }
+
+ append_create_options(thd, packet, field->option_list, check_options,
+ hton->field_options);
+
if (field->check_constraint)
{
StringBuffer<MAX_FIELD_WIDTH> str(&my_charset_utf8mb4_general_ci);
@@ -2327,13 +2337,6 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(")"));
}
- if (field->comment.length)
- {
- packet->append(STRING_WITH_LEN(" COMMENT "));
- append_unescaped(packet, field->comment.str, field->comment.length);
- }
- append_create_options(thd, packet, field->option_list, check_options,
- hton->field_options);
}
key_info= table->s->key_info;
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 9cd6c61891a..210e52887f1 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -278,7 +278,7 @@ public:
Field **nullable_fields() { return record0_field; }
void reset_extra_null_bitmap()
{
- size_t null_bytes= (trigger_table->s->stored_fields -
+ size_t null_bytes= (trigger_table->s->fields -
trigger_table->s->null_fields + 7)/8;
bzero(extra_null_bitmap, null_bytes);
}
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 032530deebc..94b0ab9a6c1 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -4490,7 +4490,7 @@ void Type_handler_temporal_result::Item_get_date(THD *thd, Item *item,
longlong Type_handler_real_result::
Item_val_int_signed_typecast(Item *item) const
{
- return item->val_int();
+ return item->val_int_signed_typecast_from_int();
}
longlong Type_handler_int_result::
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index e10c0af2e16..c32a6ee852f 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -2049,3 +2049,43 @@ void st_select_lex_unit::set_unique_exclude()
}
}
}
+
+/**
+ @brief
+ Check if the derived table is guaranteed to have distinct rows because of
+ UNION operations used to populate it.
+
+ @detail
+ UNION operation removes duplicate rows from its output. That is, a query like
+
+ select * from t1 UNION select * from t2
+
+ will not produce duplicate rows in its output, even if table t1 (and/or t2)
+ contain duplicate rows. EXCEPT and INTERSECT operations also have this
+ property.
+
+ On the other hand, UNION ALL operation doesn't remove duplicates. (The SQL
+ standard also defines EXCEPT ALL and INTERSECT ALL, but we don't support
+ them).
+
+ st_select_lex_unit computes its value left to right. That is, if there is
+ a st_select_lex_unit object describing
+
+ (select #1) OP1 (select #2) OP2 (select #3)
+
+ then ((select #1) OP1 (select #2)) is computed first, and OP2 is computed
+ second.
+
+ How can one tell if st_select_lex_unit is guaranteed to have distinct
+ output rows? This depends on whether the last operation was duplicate-
+ removing or not:
+ - UNION ALL is not duplicate-removing
+ - all other operations are duplicate-removing
+*/
+
+bool st_select_lex_unit::check_distinct_in_union()
+{
+ if (union_distinct && !union_distinct->next_select())
+ return true;
+ return false;
+}
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 14d5ae85462..2e92838ad3a 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -3206,6 +3206,8 @@ static Sys_var_replicate_events_marked_for_skip Replicate_events_marked_for_skip
static bool fix_rpl_semi_sync_master_enabled(sys_var *self, THD *thd,
enum_var_type type)
{
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&repl_semisync_master.LOCK_rpl_semi_sync_master_enabled);
if (rpl_semi_sync_master_enabled)
{
if (repl_semisync_master.enable_master() != 0)
@@ -3218,11 +3220,11 @@ static bool fix_rpl_semi_sync_master_enabled(sys_var *self, THD *thd,
}
else
{
- if (repl_semisync_master.disable_master() != 0)
- rpl_semi_sync_master_enabled= true;
- if (!rpl_semi_sync_master_enabled)
- ack_receiver.stop();
+ repl_semisync_master.disable_master();
+ ack_receiver.stop();
}
+ mysql_mutex_unlock(&repl_semisync_master.LOCK_rpl_semi_sync_master_enabled);
+ mysql_mutex_lock(&LOCK_global_system_variables);
return false;
}
@@ -3806,14 +3808,12 @@ bool Sys_var_tx_read_only::session_update(THD *thd, set_var *var)
#ifndef EMBEDDED_LIBRARY
if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
{
- Transaction_state_tracker *tst= (Transaction_state_tracker *)
- thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER);
-
if (var->type == OPT_DEFAULT)
- tst->set_read_flags(thd,
+ thd->session_tracker.transaction_info.set_read_flags(thd,
thd->tx_read_only ? TX_READ_ONLY : TX_READ_WRITE);
else
- tst->set_read_flags(thd, TX_READ_INHERIT);
+ thd->session_tracker.transaction_info.set_read_flags(thd,
+ TX_READ_INHERIT);
}
#endif //EMBEDDED_LIBRARY
}
@@ -6255,8 +6255,7 @@ static bool update_session_track_schema(sys_var *self, THD *thd,
enum_var_type type)
{
DBUG_ENTER("update_session_track_schema");
- DBUG_RETURN(thd->session_tracker.get_tracker(CURRENT_SCHEMA_TRACKER)->
- update(thd, NULL));
+ DBUG_RETURN(thd->session_tracker.current_schema.update(thd, NULL));
}
static Sys_var_mybool Sys_session_track_schema(
@@ -6273,8 +6272,7 @@ static bool update_session_track_tx_info(sys_var *self, THD *thd,
enum_var_type type)
{
DBUG_ENTER("update_session_track_tx_info");
- DBUG_RETURN(thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER)->
- update(thd, NULL));
+ DBUG_RETURN(thd->session_tracker.transaction_info.update(thd, NULL));
}
static const char *session_track_transaction_info_names[]=
@@ -6299,8 +6297,7 @@ static bool update_session_track_state_change(sys_var *self, THD *thd,
enum_var_type type)
{
DBUG_ENTER("update_session_track_state_change");
- DBUG_RETURN(thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->
- update(thd, NULL));
+ DBUG_RETURN(thd->session_tracker.state_change.update(thd, NULL));
}
static Sys_var_mybool Sys_session_track_state_change(
diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic
index 398dbb98455..440890bccfd 100644
--- a/sql/sys_vars.ic
+++ b/sql/sys_vars.ic
@@ -615,7 +615,7 @@ public:
char *new_val= global_update_prepare(thd, var);
if (new_val)
{
- if (sysvartrack_reprint_value(thd, new_val,
+ if (sysvartrack_global_update(thd, new_val,
var->save_result.string_value.length))
new_val= 0;
}
@@ -623,9 +623,7 @@ public:
return (new_val == 0 && var->save_result.string_value.str != 0);
}
bool session_update(THD *thd, set_var *var)
- {
- return sysvartrack_update(thd, var);
- }
+ { return thd->session_tracker.sysvars.update(thd, var); }
void session_save_default(THD *thd, set_var *var)
{
var->save_result.string_value.str= global_var(char*);
@@ -643,19 +641,6 @@ public:
DBUG_ASSERT(res == 0);
}
}
- uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base)
- {
- DBUG_ASSERT(thd != NULL);
- size_t len= sysvartrack_value_len(thd);
- char *res= (char *)thd->alloc(len + sizeof(char *));
- if (res)
- {
- char *buf= res + sizeof(char *);
- *((char**) res)= buf;
- sysvartrack_value_construct(thd, buf, len);
- }
- return (uchar *)res;
- }
};
#endif //EMBEDDED_LIBRARY
@@ -2229,14 +2214,6 @@ public:
return TRUE;
if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction())
{
-#ifndef EMBEDDED_LIBRARY
- Transaction_state_tracker *tst= NULL;
-
- if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
- tst= (Transaction_state_tracker *)
- thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER);
-#endif //EMBEDDED_LIBRARY
-
thd->tx_isolation= (enum_tx_isolation) var->save_result.ulonglong_value;
#ifndef EMBEDDED_LIBRARY
@@ -2260,13 +2237,11 @@ public:
DBUG_ASSERT(0);
return TRUE;
}
- if (tst)
- tst->set_isol_level(thd, l);
- }
- else if (tst)
- {
- tst->set_isol_level(thd, TX_ISOL_INHERIT);
+ if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
+ thd->session_tracker.transaction_info.set_isol_level(thd, l);
}
+ else if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
+ thd->session_tracker.transaction_info.set_isol_level(thd, TX_ISOL_INHERIT);
#endif //EMBEDDED_LIBRARY
}
return FALSE;
diff --git a/sql/table.cc b/sql/table.cc
index 016fe91c805..9567ed722f1 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -7639,6 +7639,26 @@ bool TABLE::add_tmp_key(uint key, uint key_parts,
key_part_info++;
}
+ /*
+ For the case when there is a derived table that would give distinct rows,
+ the index statistics are passed to the join optimizer to tell that a ref
+ access to all the fields of the derived table will produce only one row.
+ */
+
+ st_select_lex_unit* derived= pos_in_table_list ?
+ pos_in_table_list->derived: NULL;
+ if (derived)
+ {
+ st_select_lex* first= derived->first_select();
+ uint select_list_items= first->get_item_list()->elements;
+ if (key_parts == select_list_items)
+ {
+ if ((!first->is_part_of_union() && (first->options & SELECT_DISTINCT)) ||
+ derived->check_distinct_in_union())
+ keyinfo->rec_per_key[key_parts - 1]= 1;
+ }
+ }
+
set_if_bigger(s->max_key_length, keyinfo->key_length);
s->keys++;
return FALSE;
diff --git a/sql/transaction.cc b/sql/transaction.cc
index bb8aaabbcb9..2887ae763df 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -35,10 +35,7 @@ void trans_track_end_trx(THD *thd)
{
#ifndef EMBEDDED_LIBRARY
if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
- {
- ((Transaction_state_tracker *)
- thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER))->end_trx(thd);
- }
+ thd->session_tracker.transaction_info.end_trx(thd);
#endif //EMBEDDED_LIBRARY
}
@@ -52,11 +49,8 @@ void trans_reset_one_shot_chistics(THD *thd)
#ifndef EMBEDDED_LIBRARY
if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
{
- Transaction_state_tracker *tst= (Transaction_state_tracker *)
- thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER);
-
- tst->set_read_flags(thd, TX_READ_INHERIT);
- tst->set_isol_level(thd, TX_ISOL_INHERIT);
+ thd->session_tracker.transaction_info.set_read_flags(thd, TX_READ_INHERIT);
+ thd->session_tracker.transaction_info.set_isol_level(thd, TX_ISOL_INHERIT);
}
#endif //EMBEDDED_LIBRARY
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
@@ -101,20 +95,11 @@ static bool trans_check(THD *thd)
bool trans_begin(THD *thd, uint flags)
{
int res= FALSE;
-#ifndef EMBEDDED_LIBRARY
- Transaction_state_tracker *tst= NULL;
-#endif //EMBEDDED_LIBRARY
DBUG_ENTER("trans_begin");
if (trans_check(thd))
DBUG_RETURN(TRUE);
-#ifndef EMBEDDED_LIBRARY
- if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
- tst= (Transaction_state_tracker *)
- thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER);
-#endif //EMBEDDED_LIBRARY
-
thd->locked_tables_list.unlock_locked_tables(thd);
DBUG_ASSERT(!thd->locked_tables_mode);
@@ -162,8 +147,8 @@ bool trans_begin(THD *thd, uint flags)
{
thd->tx_read_only= true;
#ifndef EMBEDDED_LIBRARY
- if (tst)
- tst->set_read_flags(thd, TX_READ_ONLY);
+ if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
+ thd->session_tracker.transaction_info.set_read_flags(thd, TX_READ_ONLY);
#endif //EMBEDDED_LIBRARY
}
else if (flags & MYSQL_START_TRANS_OPT_READ_WRITE)
@@ -187,8 +172,8 @@ bool trans_begin(THD *thd, uint flags)
just from the session's default.
*/
#ifndef EMBEDDED_LIBRARY
- if (tst)
- tst->set_read_flags(thd, TX_READ_WRITE);
+ if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
+ thd->session_tracker.transaction_info.set_read_flags(thd, TX_READ_WRITE);
#endif //EMBEDDED_LIBRARY
}
@@ -210,16 +195,16 @@ bool trans_begin(THD *thd, uint flags)
DBUG_PRINT("info", ("setting SERVER_STATUS_IN_TRANS"));
#ifndef EMBEDDED_LIBRARY
- if (tst)
- tst->add_trx_state(thd, TX_EXPLICIT);
+ if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
+ thd->session_tracker.transaction_info.add_trx_state(thd, TX_EXPLICIT);
#endif //EMBEDDED_LIBRARY
/* ha_start_consistent_snapshot() relies on OPTION_BEGIN flag set. */
if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
{
#ifndef EMBEDDED_LIBRARY
- if (tst)
- tst->add_trx_state(thd, TX_WITH_SNAPSHOT);
+ if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
+ thd->session_tracker.transaction_info.add_trx_state(thd, TX_WITH_SNAPSHOT);
#endif //EMBEDDED_LIBRARY
res= ha_start_consistent_snapshot(thd);
}
diff --git a/sql/wsrep_server_service.cc b/sql/wsrep_server_service.cc
index 14b294c4214..42856862db3 100644
--- a/sql/wsrep_server_service.cc
+++ b/sql/wsrep_server_service.cc
@@ -46,7 +46,7 @@ wsrep::storage_service* Wsrep_server_service::storage_service(
{
Wsrep_client_service& cs=
static_cast<Wsrep_client_service&>(client_service);
- THD* thd= new THD(next_thread_id(), true, true);
+ THD* thd= new THD(next_thread_id(), true);
init_service_thd(thd, cs.m_thd->thread_stack);
WSREP_DEBUG("Created storage service with thread id %llu",
thd->thread_id);
@@ -58,7 +58,7 @@ wsrep::storage_service* Wsrep_server_service::storage_service(
{
Wsrep_high_priority_service& hps=
static_cast<Wsrep_high_priority_service&>(high_priority_service);
- THD* thd= new THD(next_thread_id(), true, true);
+ THD* thd= new THD(next_thread_id(), true);
init_service_thd(thd, hps.m_thd->thread_stack);
WSREP_DEBUG("Created high priority storage service with thread id %llu",
thd->thread_id);
@@ -81,7 +81,7 @@ Wsrep_server_service::streaming_applier_service(
{
Wsrep_client_service& orig_cs=
static_cast<Wsrep_client_service&>(orig_client_service);
- THD* thd= new THD(next_thread_id(), true, true);
+ THD* thd= new THD(next_thread_id(), true);
init_service_thd(thd, orig_cs.m_thd->thread_stack);
WSREP_DEBUG("Created streaming applier service in local context with "
"thread id %llu", thd->thread_id);
@@ -94,7 +94,7 @@ Wsrep_server_service::streaming_applier_service(
{
Wsrep_high_priority_service&
orig_hps(static_cast<Wsrep_high_priority_service&>(orig_high_priority_service));
- THD* thd= new THD(next_thread_id(), true, true);
+ THD* thd= new THD(next_thread_id(), true);
init_service_thd(thd, orig_hps.m_thd->thread_stack);
WSREP_DEBUG("Created streaming applier service in high priority "
"context with thread id %llu", thd->thread_id);