diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-05-05 15:03:48 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-05-05 15:06:44 +0300 |
commit | d3dcec5d657b83ca08b32f5a64b5dff01edfb13e (patch) | |
tree | 5fd801aa0daf5e74689b17ed50a086a8acd7d6e7 /sql | |
parent | b132b8895e2e59df457e063451f186b53576b034 (diff) | |
parent | e8dd18a474ee6b48eb7f92e3831f9e359b0bdc6e (diff) | |
download | mariadb-git-d3dcec5d657b83ca08b32f5a64b5dff01edfb13e.tar.gz |
Merge 10.3 into 10.4
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 11 | ||||
-rw-r--r-- | sql/item.h | 7 | ||||
-rw-r--r-- | sql/item_sum.cc | 14 | ||||
-rw-r--r-- | sql/lock.cc | 11 | ||||
-rw-r--r-- | sql/log.cc | 2 | ||||
-rw-r--r-- | sql/mysqld.cc | 17 | ||||
-rw-r--r-- | sql/semisync_master.cc | 11 | ||||
-rw-r--r-- | sql/semisync_master.h | 8 | ||||
-rw-r--r-- | sql/semisync_master_ack_receiver.cc | 3 | ||||
-rw-r--r-- | sql/session_tracker.cc | 765 | ||||
-rw-r--r-- | sql/session_tracker.h | 287 | ||||
-rw-r--r-- | sql/set_var.cc | 8 | ||||
-rw-r--r-- | sql/set_var.h | 3 | ||||
-rw-r--r-- | sql/signal_handler.cc | 46 | ||||
-rw-r--r-- | sql/sql_acl.cc | 4 | ||||
-rw-r--r-- | sql/sql_analyze_stmt.cc | 10 | ||||
-rw-r--r-- | sql/sql_class.cc | 22 | ||||
-rw-r--r-- | sql/sql_class.h | 11 | ||||
-rw-r--r-- | sql/sql_lex.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.h | 1 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 47 | ||||
-rw-r--r-- | sql/sql_plugin.h | 3 | ||||
-rw-r--r-- | sql/sql_show.cc | 17 | ||||
-rw-r--r-- | sql/sql_trigger.h | 2 | ||||
-rw-r--r-- | sql/sql_type.cc | 2 | ||||
-rw-r--r-- | sql/sql_union.cc | 40 | ||||
-rw-r--r-- | sql/sys_vars.cc | 27 | ||||
-rw-r--r-- | sql/sys_vars.ic | 37 | ||||
-rw-r--r-- | sql/table.cc | 20 | ||||
-rw-r--r-- | sql/transaction.cc | 37 | ||||
-rw-r--r-- | sql/wsrep_server_service.cc | 8 |
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]= ¤t_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 >id) #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); |